1
0
mirror of https://github.com/tooot-app/app synced 2025-02-21 06:10:54 +01:00
This commit is contained in:
Zhiyuan Zheng 2021-03-13 17:56:57 +01:00
parent 2620ec52bb
commit bde6c77cc1
No known key found for this signature in database
GPG Key ID: 078A93AB607D85E0
3 changed files with 126 additions and 151 deletions

View File

@ -46,7 +46,6 @@
"expo-firebase-analytics": "~2.6.0", "expo-firebase-analytics": "~2.6.0",
"expo-haptics": "~8.4.0", "expo-haptics": "~8.4.0",
"expo-image-picker": "~9.2.0", "expo-image-picker": "~9.2.0",
"expo-linear-gradient": "~8.4.0",
"expo-linking": "~2.0.1", "expo-linking": "~2.0.1",
"expo-localization": "~9.1.0", "expo-localization": "~9.1.0",
"expo-notifications": "~0.8.2", "expo-notifications": "~0.8.2",

View File

@ -9,10 +9,9 @@ import { StyleConstants } from '@utils/styles/constants'
import layoutAnimation from '@utils/styles/layoutAnimation' import layoutAnimation from '@utils/styles/layoutAnimation'
import { adaptiveScale } from '@utils/styles/scaling' import { adaptiveScale } from '@utils/styles/scaling'
import { useTheme } from '@utils/styles/ThemeManager' import { useTheme } from '@utils/styles/ThemeManager'
import { LinearGradient } from 'expo-linear-gradient'
import React, { useCallback, useState } from 'react' import React, { useCallback, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { Platform, Pressable, Text, View } from 'react-native' import { Pressable, Text, View } from 'react-native'
import HTMLView from 'react-native-htmlview' import HTMLView from 'react-native-htmlview'
import { useSelector } from 'react-redux' import { useSelector } from 'react-redux'
@ -164,120 +163,102 @@ export interface Props {
disableDetails?: boolean disableDetails?: boolean
} }
const ParseHTML: React.FC<Props> = ({ const ParseHTML = React.memo(
content, ({
size = 'M', content,
adaptiveSize = false, size = 'M',
emojis, adaptiveSize = false,
mentions, emojis,
tags, mentions,
showFullLink = false, tags,
numberOfLines = 10, showFullLink = false,
expandHint, numberOfLines = 10,
disableDetails = false expandHint,
}) => { disableDetails = false
const adaptiveFontsize = useSelector(getSettingsFontsize) }: Props) => {
const adaptedFontsize = adaptiveScale( const adaptiveFontsize = useSelector(getSettingsFontsize)
StyleConstants.Font.Size[size], const adaptedFontsize = adaptiveScale(
adaptiveSize ? adaptiveFontsize : 0 StyleConstants.Font.Size[size],
) adaptiveSize ? adaptiveFontsize : 0
const adaptedLineheight = adaptiveScale( )
StyleConstants.Font.LineHeight[size], const adaptedLineheight = adaptiveScale(
adaptiveSize ? adaptiveFontsize : 0 StyleConstants.Font.LineHeight[size],
) adaptiveSize ? adaptiveFontsize : 0
)
const navigation = useNavigation< const navigation = useNavigation<
StackNavigationProp<Nav.TabLocalStackParamList> StackNavigationProp<Nav.TabLocalStackParamList>
>() >()
const route = useRoute() const route = useRoute()
const { theme } = useTheme() const { mode, theme } = useTheme()
const { t, i18n } = useTranslation('componentParse') const { t, i18n } = useTranslation('componentParse')
if (!expandHint) { if (!expandHint) {
expandHint = t('HTML.defaultHint') expandHint = t('HTML.defaultHint')
}
const renderNodeCallback = useCallback(
(node, index) =>
renderNode({
routeParams: route.params,
theme,
node,
index,
adaptedFontsize,
adaptedLineheight,
navigation,
mentions,
tags,
showFullLink,
disableDetails
}),
[]
)
const textComponent = useCallback(({ children }) => {
if (children) {
return (
<ParseEmojis
content={children.toString()}
emojis={emojis}
size={size}
adaptiveSize={adaptiveSize}
/>
)
} else {
return null
} }
}, [])
const rootComponent = useCallback(
({ children }) => {
const { t } = useTranslation('componentParse')
const [expandAllow, setExpandAllow] = useState(false) const renderNodeCallback = useCallback(
const [expanded, setExpanded] = useState(false) (node, index) =>
renderNode({
const onTextLayout = useCallback(({ nativeEvent }) => { routeParams: route.params,
switch (Platform.OS) { theme,
case 'ios': node,
if (nativeEvent.lines.length === numberOfLines + 1) { index,
setExpandAllow(true) adaptedFontsize,
} adaptedLineheight,
break navigation,
case 'android': mentions,
if (nativeEvent.lines.length > numberOfLines + 1) { tags,
setExpandAllow(true) showFullLink,
} disableDetails
break }),
} []
}, []) )
const textComponent = useCallback(({ children }) => {
return ( if (children) {
<View style={{ overflow: 'hidden' }}> return (
<Text <ParseEmojis
children={children} content={children.toString()}
onTextLayout={onTextLayout} emojis={emojis}
numberOfLines={expanded ? 999 : numberOfLines + 1} size={size}
adaptiveSize={adaptiveSize}
/> />
{expandAllow ? ( )
<Pressable } else {
onPress={() => { return null
analytics('status_readmore', { allow: expandAllow, expanded }) }
layoutAnimation() }, [])
setExpanded(!expanded) const rootComponent = useCallback(
}} ({ children }) => {
style={{ const { t } = useTranslation('componentParse')
marginTop: expanded
? 0 const [expandAllow, setExpandAllow] = useState(false)
: -adaptedLineheight * (numberOfLines === 0 ? 1 : 2) const [expanded, setExpanded] = useState(false)
}}
> const onTextLayout = useCallback(({ nativeEvent }) => {
<LinearGradient if (nativeEvent.lines.length >= numberOfLines) {
colors={[ setExpandAllow(true)
theme.backgroundGradientStart, }
theme.backgroundGradientEnd }, [])
]}
locations={[0, adaptedLineheight / (adaptedFontsize * 5)]} return (
<View style={{ overflow: 'hidden' }}>
<Text
children={children}
onTextLayout={onTextLayout}
numberOfLines={expanded ? 999 : numberOfLines}
/>
{expandAllow ? (
<Pressable
onPress={() => {
analytics('status_readmore', { allow: expandAllow, expanded })
layoutAnimation()
setExpanded(!expanded)
}}
style={{ style={{
paddingTop: StyleConstants.Font.Size.S * 2, justifyContent: 'center',
paddingBottom: StyleConstants.Font.Size.S marginTop: expanded ? 0 : -adaptedLineheight,
minHeight: 44,
backgroundColor: theme.background
}} }}
> >
<Text <Text
@ -286,29 +267,28 @@ const ParseHTML: React.FC<Props> = ({
...StyleConstants.FontStyle.S, ...StyleConstants.FontStyle.S,
color: theme.primary color: theme.primary
}} }}
> children={t(`HTML.expanded.${expanded.toString()}`, {
{expanded hint: expandHint
? t('HTML.expanded.true', { hint: expandHint }) })}
: t('HTML.expanded.false', { hint: expandHint })} />
</Text> </Pressable>
</LinearGradient> ) : null}
</Pressable> </View>
) : null} )
</View> },
) [mode, i18n.language]
}, )
[theme, i18n.language]
)
return ( return (
<HTMLView <HTMLView
value={content} value={content}
TextComponent={textComponent} TextComponent={textComponent}
RootComponent={rootComponent} RootComponent={rootComponent}
renderNode={renderNodeCallback} renderNode={renderNodeCallback}
/> />
) )
} },
() => true
)
// export default ParseHTML export default ParseHTML
export default React.memo(ParseHTML, () => true)

View File

@ -1,8 +1,6 @@
import { ParseHTML } from '@components/Parse' import { ParseHTML } from '@components/Parse'
import { StyleConstants } from '@utils/styles/constants'
import React from 'react' import React from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { View } from 'react-native'
export interface Props { export interface Props {
status: Mastodon.Status status: Mastodon.Status
@ -24,18 +22,16 @@ const TimelineContent = React.memo(
<> <>
{status.spoiler_text ? ( {status.spoiler_text ? (
<> <>
<View style={{ marginBottom: StyleConstants.Font.Size.M }}> <ParseHTML
<ParseHTML content={status.spoiler_text}
content={status.spoiler_text} size={highlighted ? 'L' : 'M'}
size={highlighted ? 'L' : 'M'} adaptiveSize
adaptiveSize emojis={status.emojis}
emojis={status.emojis} mentions={status.mentions}
mentions={status.mentions} tags={status.tags}
tags={status.tags} numberOfLines={999}
numberOfLines={999} disableDetails={disableDetails}
disableDetails={disableDetails} />
/>
</View>
<ParseHTML <ParseHTML
content={status.content} content={status.content}
size={highlighted ? 'L' : 'M'} size={highlighted ? 'L' : 'M'}
@ -43,7 +39,7 @@ const TimelineContent = React.memo(
emojis={status.emojis} emojis={status.emojis}
mentions={status.mentions} mentions={status.mentions}
tags={status.tags} tags={status.tags}
numberOfLines={0} numberOfLines={1}
expandHint={t('shared.content.expandHint')} expandHint={t('shared.content.expandHint')}
disableDetails={disableDetails} disableDetails={disableDetails}
/> />