mirror of
https://github.com/tooot-app/app
synced 2025-06-05 22:19:13 +02:00
Using new text component
Need to use global accessibility checks rather than per text component which is not efficient
This commit is contained in:
@ -5,9 +5,10 @@ import { TabLocalStackParamList } from '@utils/navigation/navigators'
|
||||
import { StyleConstants } from '@utils/styles/constants'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import React, { useCallback } from 'react'
|
||||
import { Pressable, StyleSheet, Text, View } from 'react-native'
|
||||
import { Pressable, View } from 'react-native'
|
||||
import analytics from './analytics'
|
||||
import GracefullyImage from './GracefullyImage'
|
||||
import CustomText from './Text'
|
||||
|
||||
export interface Props {
|
||||
account: Mastodon.Account
|
||||
@ -32,50 +33,45 @@ const ComponentAccount: React.FC<Props> = ({
|
||||
return (
|
||||
<Pressable
|
||||
accessibilityRole='button'
|
||||
style={[styles.itemDefault, styles.itemAccount]}
|
||||
style={{
|
||||
paddingHorizontal: StyleConstants.Spacing.Global.PagePadding,
|
||||
paddingVertical: StyleConstants.Spacing.M,
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center'
|
||||
}}
|
||||
onPress={customOnPress || onPress}
|
||||
>
|
||||
<GracefullyImage
|
||||
uri={{ original: account.avatar, static: account.avatar_static }}
|
||||
style={styles.itemAccountAvatar}
|
||||
style={{
|
||||
alignSelf: 'flex-start',
|
||||
width: StyleConstants.Avatar.S,
|
||||
height: StyleConstants.Avatar.S,
|
||||
borderRadius: 6,
|
||||
marginRight: StyleConstants.Spacing.S
|
||||
}}
|
||||
/>
|
||||
<View>
|
||||
<Text numberOfLines={1}>
|
||||
<CustomText numberOfLines={1}>
|
||||
<ParseEmojis
|
||||
content={account.display_name || account.username}
|
||||
emojis={account.emojis}
|
||||
size='S'
|
||||
fontBold
|
||||
/>
|
||||
</Text>
|
||||
<Text
|
||||
</CustomText>
|
||||
<CustomText
|
||||
numberOfLines={1}
|
||||
style={[styles.itemAccountAcct, { color: colors.secondary }]}
|
||||
style={{
|
||||
marginTop: StyleConstants.Spacing.XS,
|
||||
color: colors.secondary
|
||||
}}
|
||||
>
|
||||
@{account.acct}
|
||||
</Text>
|
||||
</CustomText>
|
||||
</View>
|
||||
</Pressable>
|
||||
)
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
itemDefault: {
|
||||
paddingHorizontal: StyleConstants.Spacing.Global.PagePadding,
|
||||
paddingVertical: StyleConstants.Spacing.M
|
||||
},
|
||||
itemAccount: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center'
|
||||
},
|
||||
itemAccountAvatar: {
|
||||
alignSelf: 'flex-start',
|
||||
width: StyleConstants.Avatar.S,
|
||||
height: StyleConstants.Avatar.S,
|
||||
borderRadius: 6,
|
||||
marginRight: StyleConstants.Spacing.S
|
||||
},
|
||||
itemAccountAcct: { marginTop: StyleConstants.Spacing.XS }
|
||||
})
|
||||
|
||||
export default ComponentAccount
|
||||
|
@ -7,12 +7,11 @@ import {
|
||||
AccessibilityProps,
|
||||
Pressable,
|
||||
StyleProp,
|
||||
StyleSheet,
|
||||
Text,
|
||||
View,
|
||||
ViewStyle
|
||||
} from 'react-native'
|
||||
import { Flow } from 'react-native-animated-spinkit'
|
||||
import CustomText from './Text'
|
||||
|
||||
export interface Props {
|
||||
accessibilityLabel?: AccessibilityProps['accessibilityLabel']
|
||||
@ -116,7 +115,7 @@ const Button: React.FC<Props> = ({
|
||||
case 'text':
|
||||
return (
|
||||
<>
|
||||
<Text
|
||||
<CustomText
|
||||
style={{
|
||||
color: mainColor,
|
||||
fontSize:
|
||||
@ -146,8 +145,10 @@ const Button: React.FC<Props> = ({
|
||||
busy: loading
|
||||
}}
|
||||
style={[
|
||||
styles.button,
|
||||
{
|
||||
borderRadius: 100,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
borderWidth: overlay ? 0 : 1,
|
||||
borderColor: mainColor,
|
||||
backgroundColor: colorBackground,
|
||||
@ -170,12 +171,4 @@ const Button: React.FC<Props> = ({
|
||||
)
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
button: {
|
||||
borderRadius: 100,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center'
|
||||
}
|
||||
})
|
||||
|
||||
export default Button
|
||||
|
@ -1,3 +1,4 @@
|
||||
import CustomText from '@components/Text'
|
||||
import { useAppDispatch } from '@root/store'
|
||||
import { useAccessibility } from '@utils/accessibility/AccessibilityManager'
|
||||
import { countInstanceEmoji } from '@utils/slices/instancesSlice'
|
||||
@ -11,8 +12,6 @@ import {
|
||||
findNodeHandle,
|
||||
Pressable,
|
||||
SectionList,
|
||||
StyleSheet,
|
||||
Text,
|
||||
View
|
||||
} from 'react-native'
|
||||
import FastImage from 'react-native-fast-image'
|
||||
@ -30,7 +29,12 @@ const EmojisList = React.memo(
|
||||
|
||||
const listHeader = useCallback(
|
||||
({ section: { title } }) => (
|
||||
<Text style={[styles.group, { color: colors.secondary }]}>{title}</Text>
|
||||
<CustomText
|
||||
fontStyle='S'
|
||||
style={{ position: 'absolute', color: colors.secondary }}
|
||||
>
|
||||
{title}
|
||||
</CustomText>
|
||||
),
|
||||
[]
|
||||
)
|
||||
@ -38,7 +42,15 @@ const EmojisList = React.memo(
|
||||
const listItem = useCallback(
|
||||
({ index, item }: { item: Mastodon.Emoji[]; index: number }) => {
|
||||
return (
|
||||
<View key={index} style={styles.emojis}>
|
||||
<View
|
||||
key={index}
|
||||
style={{
|
||||
flex: 1,
|
||||
flexWrap: 'wrap',
|
||||
marginTop: StyleConstants.Spacing.M,
|
||||
marginRight: StyleConstants.Spacing.S
|
||||
}}
|
||||
>
|
||||
{item.map(emoji => {
|
||||
const uri = reduceMotionEnabled ? emoji.static_url : emoji.url
|
||||
if (validUrl.isHttpsUri(uri)) {
|
||||
@ -64,7 +76,12 @@ const EmojisList = React.memo(
|
||||
'screenCompose:content.root.footer.emojis.accessibilityHint'
|
||||
)}
|
||||
source={{ uri }}
|
||||
style={styles.emoji}
|
||||
style={{
|
||||
width: 32,
|
||||
height: 32,
|
||||
padding: StyleConstants.Spacing.S,
|
||||
margin: StyleConstants.Spacing.S
|
||||
}}
|
||||
/>
|
||||
</Pressable>
|
||||
)
|
||||
@ -104,23 +121,4 @@ const EmojisList = React.memo(
|
||||
() => true
|
||||
)
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
group: {
|
||||
position: 'absolute',
|
||||
...StyleConstants.FontStyle.S
|
||||
},
|
||||
emojis: {
|
||||
flex: 1,
|
||||
flexWrap: 'wrap',
|
||||
marginTop: StyleConstants.Spacing.M,
|
||||
marginRight: StyleConstants.Spacing.S
|
||||
},
|
||||
emoji: {
|
||||
width: 32,
|
||||
height: 32,
|
||||
padding: StyleConstants.Spacing.S,
|
||||
margin: StyleConstants.Spacing.S
|
||||
}
|
||||
})
|
||||
|
||||
export default EmojisList
|
||||
|
@ -4,8 +4,9 @@ import { TabLocalStackParamList } from '@utils/navigation/navigators'
|
||||
import { StyleConstants } from '@utils/styles/constants'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import React, { useCallback } from 'react'
|
||||
import { Pressable, StyleSheet, Text } from 'react-native'
|
||||
import { Pressable } from 'react-native'
|
||||
import analytics from './analytics'
|
||||
import CustomText from './Text'
|
||||
|
||||
export interface Props {
|
||||
hashtag: Mastodon.Tag
|
||||
@ -30,23 +31,14 @@ const ComponentHashtag: React.FC<Props> = ({
|
||||
return (
|
||||
<Pressable
|
||||
accessibilityRole='button'
|
||||
style={styles.itemDefault}
|
||||
style={{ padding: StyleConstants.Spacing.S * 1.5 }}
|
||||
onPress={customOnPress || onPress}
|
||||
>
|
||||
<Text style={[styles.itemHashtag, { color: colors.primaryDefault }]}>
|
||||
<CustomText fontStyle='M' style={{ color: colors.primaryDefault }}>
|
||||
#{hashtag.name}
|
||||
</Text>
|
||||
</CustomText>
|
||||
</Pressable>
|
||||
)
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
itemDefault: {
|
||||
padding: StyleConstants.Spacing.S * 1.5
|
||||
},
|
||||
itemHashtag: {
|
||||
...StyleConstants.FontStyle.M
|
||||
}
|
||||
})
|
||||
|
||||
export default ComponentHashtag
|
||||
|
@ -1,7 +1,7 @@
|
||||
import CustomText from '@components/Text'
|
||||
import { StyleConstants } from '@utils/styles/constants'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import React from 'react'
|
||||
import { StyleSheet, Text } from 'react-native'
|
||||
|
||||
export interface Props {
|
||||
content: string
|
||||
@ -14,11 +14,12 @@ const HeaderCenter = React.memo(
|
||||
const { colors } = useTheme()
|
||||
|
||||
return (
|
||||
<Text
|
||||
style={[
|
||||
styles.text,
|
||||
{ color: inverted ? colors.primaryOverlay : colors.primaryDefault }
|
||||
]}
|
||||
<CustomText
|
||||
style={{
|
||||
fontSize: 18,
|
||||
fontWeight: StyleConstants.Font.Weight.Bold,
|
||||
color: inverted ? colors.primaryOverlay : colors.primaryDefault
|
||||
}}
|
||||
children={content}
|
||||
/>
|
||||
)
|
||||
@ -26,11 +27,4 @@ const HeaderCenter = React.memo(
|
||||
(prev, next) => prev.content === next.content
|
||||
)
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
text: {
|
||||
fontSize: 18,
|
||||
fontWeight: StyleConstants.Font.Weight.Bold
|
||||
}
|
||||
})
|
||||
|
||||
export default HeaderCenter
|
||||
|
@ -1,8 +1,9 @@
|
||||
import Icon from '@components/Icon'
|
||||
import CustomText from '@components/Text'
|
||||
import { StyleConstants } from '@utils/styles/constants'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import React, { useMemo } from 'react'
|
||||
import { Pressable, StyleSheet, Text } from 'react-native'
|
||||
import { Pressable } from 'react-native'
|
||||
|
||||
export interface Props {
|
||||
type?: 'icon' | 'text'
|
||||
@ -34,8 +35,9 @@ const HeaderLeft: React.FC<Props> = ({
|
||||
)
|
||||
case 'text':
|
||||
return (
|
||||
<Text
|
||||
style={[styles.text, { color: colors.primaryDefault }]}
|
||||
<CustomText
|
||||
fontStyle='M'
|
||||
style={{ color: colors.primaryDefault }}
|
||||
children={content}
|
||||
/>
|
||||
)
|
||||
@ -46,38 +48,27 @@ const HeaderLeft: React.FC<Props> = ({
|
||||
<Pressable
|
||||
onPress={onPress}
|
||||
children={children}
|
||||
style={[
|
||||
styles.base,
|
||||
{
|
||||
backgroundColor: background
|
||||
? colors.backgroundOverlayDefault
|
||||
: undefined,
|
||||
minHeight: 44,
|
||||
minWidth: 44,
|
||||
marginLeft: native
|
||||
? -StyleConstants.Spacing.S
|
||||
: StyleConstants.Spacing.S,
|
||||
...(type === 'icon' && {
|
||||
borderRadius: 100
|
||||
}),
|
||||
...(type === 'text' && {
|
||||
paddingHorizontal: StyleConstants.Spacing.S
|
||||
})
|
||||
}
|
||||
]}
|
||||
style={{
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
backgroundColor: background
|
||||
? colors.backgroundOverlayDefault
|
||||
: undefined,
|
||||
minHeight: 44,
|
||||
minWidth: 44,
|
||||
marginLeft: native
|
||||
? -StyleConstants.Spacing.S
|
||||
: StyleConstants.Spacing.S,
|
||||
...(type === 'icon' && {
|
||||
borderRadius: 100
|
||||
}),
|
||||
...(type === 'text' && {
|
||||
paddingHorizontal: StyleConstants.Spacing.S
|
||||
})
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
base: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center'
|
||||
},
|
||||
text: {
|
||||
...StyleConstants.FontStyle.M
|
||||
}
|
||||
})
|
||||
|
||||
export default HeaderLeft
|
||||
|
@ -1,14 +1,9 @@
|
||||
import Icon from '@components/Icon'
|
||||
import CustomText from '@components/Text'
|
||||
import { StyleConstants } from '@utils/styles/constants'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import React, { useMemo } from 'react'
|
||||
import {
|
||||
AccessibilityProps,
|
||||
Pressable,
|
||||
StyleSheet,
|
||||
Text,
|
||||
View
|
||||
} from 'react-native'
|
||||
import { AccessibilityProps, Pressable, View } from 'react-native'
|
||||
import { Flow } from 'react-native-animated-spinkit'
|
||||
|
||||
export interface Props {
|
||||
@ -72,14 +67,12 @@ const HeaderRight: React.FC<Props> = ({
|
||||
case 'text':
|
||||
return (
|
||||
<>
|
||||
<Text
|
||||
style={[
|
||||
styles.text,
|
||||
{
|
||||
color: disabled ? colors.secondary : colors.primaryDefault,
|
||||
opacity: loading ? 0 : 1
|
||||
}
|
||||
]}
|
||||
<CustomText
|
||||
fontStyle='M'
|
||||
style={{
|
||||
color: disabled ? colors.secondary : colors.primaryDefault,
|
||||
opacity: loading ? 0 : 1
|
||||
}}
|
||||
children={content}
|
||||
/>
|
||||
{loading && loadingSpinkit}
|
||||
@ -97,38 +90,27 @@ const HeaderRight: React.FC<Props> = ({
|
||||
onPress={onPress}
|
||||
children={children}
|
||||
disabled={disabled || loading}
|
||||
style={[
|
||||
styles.base,
|
||||
{
|
||||
backgroundColor: background
|
||||
? colors.backgroundOverlayDefault
|
||||
: undefined,
|
||||
minHeight: 44,
|
||||
minWidth: 44,
|
||||
marginRight: native
|
||||
? -StyleConstants.Spacing.S
|
||||
: StyleConstants.Spacing.S,
|
||||
...(type === 'icon' && {
|
||||
borderRadius: 100
|
||||
}),
|
||||
...(type === 'text' && {
|
||||
paddingHorizontal: StyleConstants.Spacing.S
|
||||
})
|
||||
}
|
||||
]}
|
||||
style={{
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
backgroundColor: background
|
||||
? colors.backgroundOverlayDefault
|
||||
: undefined,
|
||||
minHeight: 44,
|
||||
minWidth: 44,
|
||||
marginRight: native
|
||||
? -StyleConstants.Spacing.S
|
||||
: StyleConstants.Spacing.S,
|
||||
...(type === 'icon' && {
|
||||
borderRadius: 100
|
||||
}),
|
||||
...(type === 'text' && {
|
||||
paddingHorizontal: StyleConstants.Spacing.S
|
||||
})
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
base: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center'
|
||||
},
|
||||
text: {
|
||||
...StyleConstants.FontStyle.M
|
||||
}
|
||||
})
|
||||
|
||||
export default HeaderRight
|
||||
|
@ -9,17 +9,11 @@ import React, {
|
||||
useRef,
|
||||
useState
|
||||
} from 'react'
|
||||
import {
|
||||
Platform,
|
||||
StyleSheet,
|
||||
Text,
|
||||
TextInput,
|
||||
TextInputProps,
|
||||
View
|
||||
} from 'react-native'
|
||||
import { Platform, TextInput, TextInputProps, View } from 'react-native'
|
||||
import Animated, { useAnimatedStyle, withTiming } from 'react-native-reanimated'
|
||||
import { ComponentEmojis, EmojisButton, EmojisList } from './Emojis'
|
||||
import EmojisContext from './Emojis/helpers/EmojisContext'
|
||||
import CustomText from './Text'
|
||||
|
||||
export interface Props {
|
||||
autoFocus?: boolean
|
||||
@ -106,14 +100,14 @@ const Input: React.FC<Props> = ({
|
||||
maxLength={options?.maxLength}
|
||||
>
|
||||
<View
|
||||
style={[
|
||||
styles.base,
|
||||
{
|
||||
borderColor: colors.border,
|
||||
flexDirection: multiline ? 'column' : 'row',
|
||||
alignItems: 'stretch'
|
||||
}
|
||||
]}
|
||||
style={{
|
||||
borderWidth: 1,
|
||||
marginVertical: StyleConstants.Spacing.S,
|
||||
padding: StyleConstants.Spacing.S,
|
||||
borderColor: colors.border,
|
||||
flexDirection: multiline ? 'column' : 'row',
|
||||
alignItems: 'stretch'
|
||||
}}
|
||||
>
|
||||
<EmojisContext.Consumer>
|
||||
{({ emojisDispatch }) => (
|
||||
@ -124,16 +118,15 @@ const Input: React.FC<Props> = ({
|
||||
setInputFocused(false)
|
||||
emojisDispatch({ type: 'activate', payload: false })
|
||||
}}
|
||||
style={[
|
||||
styles.textInput,
|
||||
{
|
||||
color: colors.primaryDefault,
|
||||
minHeight:
|
||||
Platform.OS === 'ios' && multiline
|
||||
? StyleConstants.Font.LineHeight.M * 5
|
||||
: undefined
|
||||
}
|
||||
]}
|
||||
style={{
|
||||
flex: 1,
|
||||
fontSize: StyleConstants.Font.Size.M,
|
||||
color: colors.primaryDefault,
|
||||
minHeight:
|
||||
Platform.OS === 'ios' && multiline
|
||||
? StyleConstants.Font.LineHeight.M * 5
|
||||
: undefined
|
||||
}}
|
||||
onChangeText={setValue}
|
||||
onSelectionChange={onSelectionChange}
|
||||
value={value}
|
||||
@ -149,16 +142,25 @@ const Input: React.FC<Props> = ({
|
||||
</EmojisContext.Consumer>
|
||||
{title ? (
|
||||
<Animated.Text
|
||||
style={[styles.title, animateTitle, { color: colors.secondary }]}
|
||||
style={[
|
||||
animateTitle,
|
||||
{ position: 'absolute', color: colors.secondary }
|
||||
]}
|
||||
>
|
||||
{title}
|
||||
</Animated.Text>
|
||||
) : null}
|
||||
<View style={{ flexDirection: 'row', alignSelf: 'flex-end' }}>
|
||||
{options?.maxLength && value?.length ? (
|
||||
<Text style={[styles.maxLength, { color: colors.secondary }]}>
|
||||
<CustomText
|
||||
fontStyle='S'
|
||||
style={{
|
||||
paddingLeft: StyleConstants.Spacing.XS,
|
||||
color: colors.secondary
|
||||
}}
|
||||
>
|
||||
{value?.length} / {options.maxLength}
|
||||
</Text>
|
||||
</CustomText>
|
||||
) : null}
|
||||
{inputFocused ? <EmojisButton /> : null}
|
||||
</View>
|
||||
@ -168,24 +170,4 @@ const Input: React.FC<Props> = ({
|
||||
)
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
base: {
|
||||
alignItems: 'flex-end',
|
||||
borderWidth: 1,
|
||||
marginVertical: StyleConstants.Spacing.S,
|
||||
padding: StyleConstants.Spacing.S
|
||||
},
|
||||
title: {
|
||||
position: 'absolute'
|
||||
},
|
||||
textInput: {
|
||||
flex: 1,
|
||||
fontSize: StyleConstants.Font.Size.M
|
||||
},
|
||||
maxLength: {
|
||||
...StyleConstants.FontStyle.S,
|
||||
paddingLeft: StyleConstants.Spacing.XS
|
||||
}
|
||||
})
|
||||
|
||||
export default Input
|
||||
|
@ -15,8 +15,6 @@ import {
|
||||
Image,
|
||||
KeyboardAvoidingView,
|
||||
Platform,
|
||||
StyleSheet,
|
||||
Text,
|
||||
TextInput,
|
||||
View
|
||||
} from 'react-native'
|
||||
@ -26,6 +24,7 @@ import { Placeholder } from 'rn-placeholder'
|
||||
import analytics from './analytics'
|
||||
import InstanceAuth from './Instance/Auth'
|
||||
import InstanceInfo from './Instance/Info'
|
||||
import CustomText from './Text'
|
||||
|
||||
export interface Props {
|
||||
scrollViewRef?: RefObject<ScrollView>
|
||||
@ -134,40 +133,50 @@ const ComponentInstance: React.FC<Props> = ({
|
||||
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
|
||||
>
|
||||
{!disableHeaderImage ? (
|
||||
<View style={styles.imageContainer}>
|
||||
<View style={{ flexDirection: 'row' }}>
|
||||
<Image
|
||||
source={require('assets/images/welcome.png')}
|
||||
style={styles.image}
|
||||
style={{ resizeMode: 'contain', flex: 1, aspectRatio: 16 / 9 }}
|
||||
/>
|
||||
</View>
|
||||
) : null}
|
||||
<View style={styles.base}>
|
||||
<View style={styles.inputRow}>
|
||||
<View
|
||||
style={{
|
||||
marginTop: StyleConstants.Spacing.L,
|
||||
marginHorizontal: StyleConstants.Spacing.Global.PagePadding
|
||||
}}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
flexDirection: 'row',
|
||||
marginHorizontal: StyleConstants.Spacing.Global.PagePadding
|
||||
}}
|
||||
>
|
||||
<TextInput
|
||||
accessible={false}
|
||||
accessibilityRole='none'
|
||||
style={[
|
||||
styles.prefix,
|
||||
{
|
||||
color: colors.primaryDefault,
|
||||
borderBottomColor: instanceQuery.isError
|
||||
? colors.red
|
||||
: colors.border
|
||||
}
|
||||
]}
|
||||
style={{
|
||||
borderBottomWidth: 1,
|
||||
...StyleConstants.FontStyle.M,
|
||||
color: colors.primaryDefault,
|
||||
borderBottomColor: instanceQuery.isError
|
||||
? colors.red
|
||||
: colors.border
|
||||
}}
|
||||
editable={false}
|
||||
defaultValue='https://'
|
||||
/>
|
||||
<TextInput
|
||||
style={[
|
||||
styles.textInput,
|
||||
{
|
||||
color: colors.primaryDefault,
|
||||
borderBottomColor: instanceQuery.isError
|
||||
? colors.red
|
||||
: colors.border
|
||||
}
|
||||
]}
|
||||
style={{
|
||||
flex: 1,
|
||||
borderBottomWidth: 1,
|
||||
...StyleConstants.FontStyle.M,
|
||||
marginRight: StyleConstants.Spacing.M,
|
||||
color: colors.primaryDefault,
|
||||
borderBottomColor: instanceQuery.isError
|
||||
? colors.red
|
||||
: colors.border
|
||||
}}
|
||||
onChangeText={onChangeText}
|
||||
autoCapitalize='none'
|
||||
clearButtonMode='never'
|
||||
@ -205,9 +214,9 @@ const ComponentInstance: React.FC<Props> = ({
|
||||
content={instanceQuery.data?.title || undefined}
|
||||
potentialWidth={2}
|
||||
/>
|
||||
<View style={styles.instanceStats}>
|
||||
<View style={{ flex: 1, flexDirection: 'row' }}>
|
||||
<InstanceInfo
|
||||
style={styles.stat1}
|
||||
style={{ alignItems: 'flex-start' }}
|
||||
header={t('server.information.accounts')}
|
||||
content={
|
||||
instanceQuery.data?.stats?.user_count?.toString() || undefined
|
||||
@ -215,7 +224,7 @@ const ComponentInstance: React.FC<Props> = ({
|
||||
potentialWidth={4}
|
||||
/>
|
||||
<InstanceInfo
|
||||
style={styles.stat2}
|
||||
style={{ alignItems: 'center' }}
|
||||
header={t('server.information.statuses')}
|
||||
content={
|
||||
instanceQuery.data?.stats?.status_count?.toString() ||
|
||||
@ -224,7 +233,7 @@ const ComponentInstance: React.FC<Props> = ({
|
||||
potentialWidth={4}
|
||||
/>
|
||||
<InstanceInfo
|
||||
style={styles.stat3}
|
||||
style={{ alignItems: 'flex-end' }}
|
||||
header={t('server.information.domains')}
|
||||
content={
|
||||
instanceQuery.data?.stats?.domain_count?.toString() ||
|
||||
@ -234,15 +243,28 @@ const ComponentInstance: React.FC<Props> = ({
|
||||
/>
|
||||
</View>
|
||||
</Placeholder>
|
||||
<View style={styles.disclaimer}>
|
||||
<View
|
||||
style={{
|
||||
flexDirection: 'row',
|
||||
marginHorizontal: StyleConstants.Spacing.Global.PagePadding,
|
||||
marginVertical: StyleConstants.Spacing.M
|
||||
}}
|
||||
>
|
||||
<Icon
|
||||
name='Lock'
|
||||
size={StyleConstants.Font.Size.S}
|
||||
color={colors.secondary}
|
||||
style={styles.disclaimerIcon}
|
||||
style={{
|
||||
marginTop:
|
||||
(StyleConstants.Font.LineHeight.S -
|
||||
StyleConstants.Font.Size.S) /
|
||||
2,
|
||||
marginRight: StyleConstants.Spacing.XS
|
||||
}}
|
||||
/>
|
||||
<Text
|
||||
style={[styles.disclaimerText, { color: colors.secondary }]}
|
||||
<CustomText
|
||||
fontStyle='S'
|
||||
style={{ flex: 1, color: colors.secondary }}
|
||||
accessibilityRole='link'
|
||||
onPress={() => {
|
||||
if (screenReaderEnabled) {
|
||||
@ -254,7 +276,7 @@ const ComponentInstance: React.FC<Props> = ({
|
||||
}}
|
||||
>
|
||||
{t('server.disclaimer.base')}
|
||||
<Text
|
||||
<CustomText
|
||||
accessible
|
||||
style={{ color: colors.blue }}
|
||||
onPress={() => {
|
||||
@ -265,8 +287,8 @@ const ComponentInstance: React.FC<Props> = ({
|
||||
}}
|
||||
>
|
||||
{t('server.disclaimer.privacy')}
|
||||
</Text>
|
||||
</Text>
|
||||
</CustomText>
|
||||
</CustomText>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
@ -276,54 +298,4 @@ const ComponentInstance: React.FC<Props> = ({
|
||||
)
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
imageContainer: { flexDirection: 'row' },
|
||||
image: { resizeMode: 'contain', flex: 1, aspectRatio: 16 / 9 },
|
||||
base: {
|
||||
marginTop: StyleConstants.Spacing.L,
|
||||
marginHorizontal: StyleConstants.Spacing.Global.PagePadding
|
||||
},
|
||||
inputRow: {
|
||||
flexDirection: 'row',
|
||||
marginHorizontal: StyleConstants.Spacing.Global.PagePadding
|
||||
},
|
||||
prefix: {
|
||||
borderBottomWidth: 1,
|
||||
...StyleConstants.FontStyle.M
|
||||
},
|
||||
textInput: {
|
||||
flex: 1,
|
||||
borderBottomWidth: 1,
|
||||
...StyleConstants.FontStyle.M,
|
||||
marginRight: StyleConstants.Spacing.M
|
||||
},
|
||||
instanceStats: {
|
||||
flex: 1,
|
||||
flexDirection: 'row'
|
||||
},
|
||||
stat1: {
|
||||
alignItems: 'flex-start'
|
||||
},
|
||||
stat2: {
|
||||
alignItems: 'center'
|
||||
},
|
||||
stat3: {
|
||||
alignItems: 'flex-end'
|
||||
},
|
||||
disclaimer: {
|
||||
flexDirection: 'row',
|
||||
marginHorizontal: StyleConstants.Spacing.Global.PagePadding,
|
||||
marginVertical: StyleConstants.Spacing.M
|
||||
},
|
||||
disclaimerIcon: {
|
||||
marginTop:
|
||||
(StyleConstants.Font.LineHeight.S - StyleConstants.Font.Size.S) / 2,
|
||||
marginRight: StyleConstants.Spacing.XS
|
||||
},
|
||||
disclaimerText: {
|
||||
flex: 1,
|
||||
...StyleConstants.FontStyle.S
|
||||
}
|
||||
})
|
||||
|
||||
export default ComponentInstance
|
||||
|
@ -1,7 +1,8 @@
|
||||
import CustomText from '@components/Text'
|
||||
import { StyleConstants } from '@utils/styles/constants'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import React from 'react'
|
||||
import { StyleSheet, Text, View, ViewStyle } from 'react-native'
|
||||
import { View, ViewStyle } from 'react-native'
|
||||
import { PlaceholderLine } from 'rn-placeholder'
|
||||
|
||||
export interface Props {
|
||||
@ -16,14 +17,33 @@ const InstanceInfo = React.memo(
|
||||
const { colors } = useTheme()
|
||||
|
||||
return (
|
||||
<View style={[styles.base, style]} accessible>
|
||||
<Text style={[styles.header, { color: colors.primaryDefault }]}>
|
||||
{header}
|
||||
</Text>
|
||||
<View
|
||||
style={[
|
||||
{
|
||||
flex: 1,
|
||||
marginTop: StyleConstants.Spacing.M,
|
||||
paddingLeft: StyleConstants.Spacing.Global.PagePadding,
|
||||
paddingRight: StyleConstants.Spacing.Global.PagePadding
|
||||
},
|
||||
style
|
||||
]}
|
||||
accessible
|
||||
>
|
||||
<CustomText
|
||||
fontStyle='S'
|
||||
style={{
|
||||
fontWeight: StyleConstants.Font.Weight.Bold,
|
||||
marginBottom: StyleConstants.Spacing.XS,
|
||||
color: colors.primaryDefault
|
||||
}}
|
||||
children={header}
|
||||
/>
|
||||
{content ? (
|
||||
<Text style={[styles.content, { color: colors.primaryDefault }]}>
|
||||
{content}
|
||||
</Text>
|
||||
<CustomText
|
||||
fontStyle='M'
|
||||
style={{ color: colors.primaryDefault }}
|
||||
children={content}
|
||||
/>
|
||||
) : (
|
||||
<PlaceholderLine
|
||||
width={
|
||||
@ -43,21 +63,4 @@ const InstanceInfo = React.memo(
|
||||
(prev, next) => prev.content === next.content
|
||||
)
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
base: {
|
||||
flex: 1,
|
||||
marginTop: StyleConstants.Spacing.M,
|
||||
paddingLeft: StyleConstants.Spacing.Global.PagePadding,
|
||||
paddingRight: StyleConstants.Spacing.Global.PagePadding
|
||||
},
|
||||
header: {
|
||||
...StyleConstants.FontStyle.S,
|
||||
fontWeight: StyleConstants.Font.Weight.Bold,
|
||||
marginBottom: StyleConstants.Spacing.XS
|
||||
},
|
||||
content: {
|
||||
...StyleConstants.FontStyle.M
|
||||
}
|
||||
})
|
||||
|
||||
export default InstanceInfo
|
||||
|
@ -1,7 +1,8 @@
|
||||
import React from 'react'
|
||||
import { StyleSheet, Text, View } from 'react-native'
|
||||
import { View } from 'react-native'
|
||||
import { StyleConstants } from '@utils/styles/constants'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import CustomText from '@components/Text'
|
||||
|
||||
export interface Props {
|
||||
heading: string
|
||||
@ -11,20 +12,16 @@ const MenuHeader: React.FC<Props> = ({ heading }) => {
|
||||
const { colors } = useTheme()
|
||||
|
||||
return (
|
||||
<View style={styles.base}>
|
||||
<Text style={[styles.text, { color: colors.secondary }]}>{heading}</Text>
|
||||
<View style={{ paddingBottom: StyleConstants.Spacing.S }}>
|
||||
<CustomText
|
||||
fontStyle='S'
|
||||
fontWeight='Bold'
|
||||
style={{ color: colors.secondary }}
|
||||
>
|
||||
{heading}
|
||||
</CustomText>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
base: {
|
||||
paddingBottom: StyleConstants.Spacing.S
|
||||
},
|
||||
text: {
|
||||
...StyleConstants.FontStyle.S,
|
||||
fontWeight: StyleConstants.Font.Weight.Bold
|
||||
}
|
||||
})
|
||||
|
||||
export default MenuHeader
|
||||
|
@ -1,4 +1,5 @@
|
||||
import Icon from '@components/Icon'
|
||||
import CustomText from '@components/Text'
|
||||
import { useAccessibility } from '@utils/accessibility/AccessibilityManager'
|
||||
import { StyleConstants } from '@utils/styles/constants'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
@ -99,12 +100,13 @@ const MenuRow: React.FC<Props> = ({
|
||||
/>
|
||||
) : null}
|
||||
<View style={styles.main}>
|
||||
<Text
|
||||
style={[styles.title, { color: colors.primaryDefault }]}
|
||||
<CustomText
|
||||
fontStyle='M'
|
||||
style={{ color: colors.primaryDefault }}
|
||||
numberOfLines={1}
|
||||
>
|
||||
{title}
|
||||
</Text>
|
||||
</CustomText>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
@ -112,18 +114,15 @@ const MenuRow: React.FC<Props> = ({
|
||||
<View style={styles.back}>
|
||||
{content ? (
|
||||
typeof content === 'string' ? (
|
||||
<Text
|
||||
style={[
|
||||
styles.content,
|
||||
{
|
||||
color: colors.secondary,
|
||||
opacity: !iconBack && loading ? 0 : 1
|
||||
}
|
||||
]}
|
||||
<CustomText
|
||||
style={{
|
||||
color: colors.secondary,
|
||||
opacity: !iconBack && loading ? 0 : 1
|
||||
}}
|
||||
numberOfLines={1}
|
||||
>
|
||||
{content}
|
||||
</Text>
|
||||
</CustomText>
|
||||
) : (
|
||||
content
|
||||
)
|
||||
@ -150,9 +149,9 @@ const MenuRow: React.FC<Props> = ({
|
||||
) : null}
|
||||
</View>
|
||||
{description ? (
|
||||
<Text style={[styles.description, { color: colors.secondary }]}>
|
||||
<CustomText fontStyle='S' style={{ color: colors.secondary }}>
|
||||
{description}
|
||||
</Text>
|
||||
</CustomText>
|
||||
) : null}
|
||||
</View>
|
||||
</TapGestureHandler>
|
||||
@ -187,9 +186,6 @@ const styles = StyleSheet.create({
|
||||
main: {
|
||||
flex: 1
|
||||
},
|
||||
title: {
|
||||
...StyleConstants.FontStyle.M
|
||||
},
|
||||
description: {
|
||||
...StyleConstants.FontStyle.S
|
||||
},
|
||||
|
@ -1,10 +1,11 @@
|
||||
import CustomText from '@components/Text'
|
||||
import { useAccessibility } from '@utils/accessibility/AccessibilityManager'
|
||||
import { getSettingsFontsize } from '@utils/slices/settingsSlice'
|
||||
import { StyleConstants } from '@utils/styles/constants'
|
||||
import { adaptiveScale } from '@utils/styles/scaling'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import React, { useMemo } from 'react'
|
||||
import { StyleSheet, Text } from 'react-native'
|
||||
import { StyleSheet } from 'react-native'
|
||||
import FastImage from 'react-native-fast-image'
|
||||
import { useSelector } from 'react-redux'
|
||||
import validUrl from 'valid-url'
|
||||
@ -57,7 +58,7 @@ const ParseEmojis = React.memo(
|
||||
}, [theme, adaptiveFontsize])
|
||||
|
||||
return (
|
||||
<Text style={styles.text}>
|
||||
<CustomText style={styles.text}>
|
||||
{emojis ? (
|
||||
content
|
||||
.split(regexEmoji)
|
||||
@ -69,30 +70,34 @@ const ParseEmojis = React.memo(
|
||||
return emojiShortcode === `:${emoji.shortcode}:`
|
||||
})
|
||||
if (emojiIndex === -1) {
|
||||
return <Text key={emojiShortcode + i}>{emojiShortcode}</Text>
|
||||
return (
|
||||
<CustomText key={emojiShortcode + i}>
|
||||
{emojiShortcode}
|
||||
</CustomText>
|
||||
)
|
||||
} else {
|
||||
const uri = reduceMotionEnabled
|
||||
? emojis[emojiIndex].static_url
|
||||
: emojis[emojiIndex].url
|
||||
if (validUrl.isHttpsUri(uri)) {
|
||||
return (
|
||||
<Text key={emojiShortcode + i}>
|
||||
<CustomText key={emojiShortcode + i}>
|
||||
{i === 0 ? ' ' : undefined}
|
||||
<FastImage source={{ uri }} style={styles.image} />
|
||||
</Text>
|
||||
</CustomText>
|
||||
)
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return <Text key={i}>{str}</Text>
|
||||
return <CustomText key={i}>{str}</CustomText>
|
||||
}
|
||||
})
|
||||
) : (
|
||||
<Text>{content}</Text>
|
||||
<CustomText>{content}</CustomText>
|
||||
)}
|
||||
</Text>
|
||||
</CustomText>
|
||||
)
|
||||
},
|
||||
(prev, next) => prev.content === next.content
|
||||
|
@ -2,6 +2,7 @@ import analytics from '@components/analytics'
|
||||
import Icon from '@components/Icon'
|
||||
import openLink from '@components/openLink'
|
||||
import ParseEmojis from '@components/Parse/Emojis'
|
||||
import CustomText from '@components/Text'
|
||||
import { useNavigation, useRoute } from '@react-navigation/native'
|
||||
import { StackNavigationProp } from '@react-navigation/stack'
|
||||
import { TabLocalStackParamList } from '@utils/navigation/navigators'
|
||||
@ -12,7 +13,7 @@ import { adaptiveScale } from '@utils/styles/scaling'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import React, { useCallback, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Pressable, Text, View } from 'react-native'
|
||||
import { Pressable, View } from 'react-native'
|
||||
import HTMLView from 'react-native-htmlview'
|
||||
import { useSelector } from 'react-redux'
|
||||
|
||||
@ -53,7 +54,7 @@ const renderNode = ({
|
||||
? routeParams.hashtag !== tag[1] && routeParams.hashtag !== tag[2]
|
||||
: true
|
||||
return (
|
||||
<Text
|
||||
<CustomText
|
||||
accessible
|
||||
key={index}
|
||||
style={{
|
||||
@ -72,7 +73,7 @@ const renderNode = ({
|
||||
>
|
||||
{node.children[0].data}
|
||||
{node.children[1]?.children[0].data}
|
||||
</Text>
|
||||
</CustomText>
|
||||
)
|
||||
} else if (classes.includes('mention') && mentions) {
|
||||
const accountIndex = mentions.findIndex(
|
||||
@ -82,7 +83,7 @@ const renderNode = ({
|
||||
? routeParams.account.id !== mentions[accountIndex]?.id
|
||||
: true
|
||||
return (
|
||||
<Text
|
||||
<CustomText
|
||||
key={index}
|
||||
style={{
|
||||
color:
|
||||
@ -102,7 +103,7 @@ const renderNode = ({
|
||||
>
|
||||
{node.children[0].data}
|
||||
{node.children[1]?.children[0].data}
|
||||
</Text>
|
||||
</CustomText>
|
||||
)
|
||||
}
|
||||
} else {
|
||||
@ -113,7 +114,7 @@ const renderNode = ({
|
||||
const shouldBeTag =
|
||||
tags && tags.filter(tag => `#${tag.name}` === content).length > 0
|
||||
return (
|
||||
<Text
|
||||
<CustomText
|
||||
key={index}
|
||||
style={{
|
||||
color: colors.blue,
|
||||
@ -142,7 +143,7 @@ const renderNode = ({
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
</Text>
|
||||
</CustomText>
|
||||
)
|
||||
}
|
||||
break
|
||||
@ -252,7 +253,7 @@ const ParseHTML = React.memo(
|
||||
|
||||
return (
|
||||
<View style={{ overflow: 'hidden' }}>
|
||||
<Text
|
||||
<CustomText
|
||||
children={children}
|
||||
onTextLayout={onTextLayout}
|
||||
numberOfLines={
|
||||
@ -275,7 +276,7 @@ const ParseHTML = React.memo(
|
||||
backgroundColor: colors.backgroundDefault
|
||||
}}
|
||||
>
|
||||
<Text
|
||||
<CustomText
|
||||
style={{
|
||||
textAlign: 'center',
|
||||
...StyleConstants.FontStyle.S,
|
||||
|
76
src/components/Text.tsx
Normal file
76
src/components/Text.tsx
Normal file
@ -0,0 +1,76 @@
|
||||
import { StyleConstants } from '@utils/styles/constants'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { AccessibilityInfo, Text, TextProps, TextStyle } from 'react-native'
|
||||
|
||||
type Props =
|
||||
| {
|
||||
style?: Omit<TextStyle, 'fontSize' | 'lineHeight' | 'fontWeight'>
|
||||
fontStyle?: undefined
|
||||
fontSize?: 'S' | 'M' | 'L'
|
||||
lineHeight?: 'S' | 'M' | 'L'
|
||||
fontWeight?: 'Normal' | 'Bold'
|
||||
}
|
||||
| {
|
||||
style?: Omit<TextStyle, 'fontSize' | 'lineHeight' | 'fontWeight'>
|
||||
fontStyle: 'S' | 'M' | 'L'
|
||||
fontSize?: undefined
|
||||
lineHeight?: undefined
|
||||
fontWeight?: 'Normal' | 'Bold'
|
||||
}
|
||||
|
||||
const CustomText: React.FC<Props & TextProps> = ({
|
||||
children,
|
||||
style,
|
||||
fontStyle,
|
||||
fontSize,
|
||||
fontWeight = 'Normal',
|
||||
lineHeight,
|
||||
...rest
|
||||
}) => {
|
||||
const [isBoldText, setIsBoldText] = useState(false)
|
||||
useEffect(() => {
|
||||
const boldTextChangedSubscription = AccessibilityInfo.addEventListener(
|
||||
'boldTextChanged',
|
||||
boldTextChanged => {
|
||||
setIsBoldText(boldTextChanged)
|
||||
}
|
||||
)
|
||||
|
||||
AccessibilityInfo.isBoldTextEnabled().then(boldTextEnabled => {
|
||||
setIsBoldText(boldTextEnabled)
|
||||
})
|
||||
|
||||
return () => {
|
||||
boldTextChangedSubscription.remove()
|
||||
}
|
||||
}, [])
|
||||
enum BoldMapping {
|
||||
'Normal' = '600',
|
||||
'Bold' = '800'
|
||||
}
|
||||
|
||||
return (
|
||||
<Text
|
||||
style={[
|
||||
style,
|
||||
{ ...(fontStyle && StyleConstants.FontStyle[fontStyle]) },
|
||||
{ ...(fontSize && { fontSize: StyleConstants.Font.Size[fontSize] }) },
|
||||
{
|
||||
...(lineHeight && {
|
||||
lineHeight: StyleConstants.Font.LineHeight[lineHeight]
|
||||
})
|
||||
},
|
||||
{
|
||||
fontWeight: isBoldText
|
||||
? BoldMapping[fontWeight]
|
||||
: StyleConstants.Font.Weight[fontWeight]
|
||||
}
|
||||
]}
|
||||
{...rest}
|
||||
>
|
||||
{children}
|
||||
</Text>
|
||||
)
|
||||
}
|
||||
|
||||
export default CustomText
|
@ -1,12 +1,13 @@
|
||||
import analytics from '@components/analytics'
|
||||
import Button from '@components/Button'
|
||||
import Icon from '@components/Icon'
|
||||
import CustomText from '@components/Text'
|
||||
import { QueryKeyTimeline, useTimelineQuery } from '@utils/queryHooks/timeline'
|
||||
import { StyleConstants } from '@utils/styles/constants'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { StyleSheet, Text, View } from 'react-native'
|
||||
import { View } from 'react-native'
|
||||
import { Circle } from 'react-native-animated-spinkit'
|
||||
|
||||
export interface Props {
|
||||
@ -40,9 +41,16 @@ const TimelineEmpty = React.memo(
|
||||
size={StyleConstants.Font.Size.L}
|
||||
color={colors.primaryDefault}
|
||||
/>
|
||||
<Text style={[styles.error, { color: colors.primaryDefault }]}>
|
||||
<CustomText
|
||||
fontStyle='M'
|
||||
style={{
|
||||
marginTop: StyleConstants.Spacing.S,
|
||||
marginBottom: StyleConstants.Spacing.L,
|
||||
color: colors.primaryDefault
|
||||
}}
|
||||
>
|
||||
{t('empty.error.message')}
|
||||
</Text>
|
||||
</CustomText>
|
||||
<Button
|
||||
type='text'
|
||||
content={t('empty.error.button')}
|
||||
@ -61,9 +69,16 @@ const TimelineEmpty = React.memo(
|
||||
size={StyleConstants.Font.Size.L}
|
||||
color={colors.primaryDefault}
|
||||
/>
|
||||
<Text style={[styles.error, { color: colors.primaryDefault }]}>
|
||||
<CustomText
|
||||
fontStyle='M'
|
||||
style={{
|
||||
marginTop: StyleConstants.Spacing.S,
|
||||
marginBottom: StyleConstants.Spacing.L,
|
||||
color: colors.primaryDefault
|
||||
}}
|
||||
>
|
||||
{t('empty.success.message')}
|
||||
</Text>
|
||||
</CustomText>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@ -85,12 +100,4 @@ const TimelineEmpty = React.memo(
|
||||
() => true
|
||||
)
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
error: {
|
||||
...StyleConstants.FontStyle.M,
|
||||
marginTop: StyleConstants.Spacing.S,
|
||||
marginBottom: StyleConstants.Spacing.L
|
||||
}
|
||||
})
|
||||
|
||||
export default TimelineEmpty
|
||||
|
@ -1,10 +1,11 @@
|
||||
import Icon from '@components/Icon'
|
||||
import CustomText from '@components/Text'
|
||||
import { QueryKeyTimeline, useTimelineQuery } from '@utils/queryHooks/timeline'
|
||||
import { StyleConstants } from '@utils/styles/constants'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import React from 'react'
|
||||
import { Trans } from 'react-i18next'
|
||||
import { Text, View } from 'react-native'
|
||||
import { View } from 'react-native'
|
||||
import { Circle } from 'react-native-animated-spinkit'
|
||||
|
||||
export interface Props {
|
||||
@ -38,9 +39,7 @@ const TimelineFooter = React.memo(
|
||||
{!disableInfinity && hasNextPage ? (
|
||||
<Circle size={StyleConstants.Font.Size.L} color={colors.secondary} />
|
||||
) : (
|
||||
<Text
|
||||
style={{ ...StyleConstants.FontStyle.S, color: colors.secondary }}
|
||||
>
|
||||
<CustomText fontStyle='S' style={{ color: colors.secondary }}>
|
||||
<Trans
|
||||
i18nKey='componentTimeline:end.message'
|
||||
components={[
|
||||
@ -51,7 +50,7 @@ const TimelineFooter = React.memo(
|
||||
/>
|
||||
]}
|
||||
/>
|
||||
</Text>
|
||||
</CustomText>
|
||||
)}
|
||||
</View>
|
||||
)
|
||||
|
@ -1,8 +1,9 @@
|
||||
import CustomText from '@components/Text'
|
||||
import { StyleConstants } from '@utils/styles/constants'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Text, View } from 'react-native'
|
||||
import { View } from 'react-native'
|
||||
|
||||
const TimelineLookback = React.memo(
|
||||
() => {
|
||||
@ -19,14 +20,9 @@ const TimelineLookback = React.memo(
|
||||
backgroundColor: colors.backgroundDefault
|
||||
}}
|
||||
>
|
||||
<Text
|
||||
style={{
|
||||
...StyleConstants.FontStyle.S,
|
||||
color: colors.primaryDefault
|
||||
}}
|
||||
>
|
||||
<CustomText fontStyle='S' style={{ color: colors.primaryDefault }}>
|
||||
{t('lookback.message')}
|
||||
</Text>
|
||||
</CustomText>
|
||||
</View>
|
||||
)
|
||||
},
|
||||
|
@ -1,5 +1,6 @@
|
||||
import haptics from '@components/haptics'
|
||||
import Icon from '@components/Icon'
|
||||
import CustomText from '@components/Text'
|
||||
import {
|
||||
QueryKeyTimeline,
|
||||
TimelineData,
|
||||
@ -9,7 +10,7 @@ import { StyleConstants } from '@utils/styles/constants'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import React, { RefObject, useCallback, useRef, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { FlatList, Platform, StyleSheet, Text, View } from 'react-native'
|
||||
import { FlatList, Platform, View } from 'react-native'
|
||||
import { Circle } from 'react-native-animated-spinkit'
|
||||
import Animated, {
|
||||
Extrapolate,
|
||||
@ -251,9 +252,18 @@ const TimelineRefresh: React.FC<Props> = ({
|
||||
|
||||
return (
|
||||
<Animated.View style={headerPadding}>
|
||||
<View style={styles.base}>
|
||||
<View
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
height: CONTAINER_HEIGHT * 2,
|
||||
alignItems: 'center'
|
||||
}}
|
||||
>
|
||||
{isFetching ? (
|
||||
<View style={styles.container2}>
|
||||
<View style={{ height: CONTAINER_HEIGHT, justifyContent: 'center' }}>
|
||||
<Circle
|
||||
size={StyleConstants.Font.Size.L}
|
||||
color={colors.secondary}
|
||||
@ -261,9 +271,19 @@ const TimelineRefresh: React.FC<Props> = ({
|
||||
</View>
|
||||
) : (
|
||||
<>
|
||||
<View style={styles.container1}>
|
||||
<Text
|
||||
style={[styles.explanation, { color: colors.primaryDefault }]}
|
||||
<View
|
||||
style={{
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
height: CONTAINER_HEIGHT
|
||||
}}
|
||||
>
|
||||
<CustomText
|
||||
fontStyle='S'
|
||||
style={{
|
||||
lineHeight: CONTAINER_HEIGHT,
|
||||
color: colors.primaryDefault
|
||||
}}
|
||||
onLayout={onLayout}
|
||||
children={t('refresh.fetchPreviousPage')}
|
||||
/>
|
||||
@ -285,9 +305,15 @@ const TimelineRefresh: React.FC<Props> = ({
|
||||
}
|
||||
/>
|
||||
</View>
|
||||
<View style={styles.container2}>
|
||||
<Text
|
||||
style={[styles.explanation, { color: colors.primaryDefault }]}
|
||||
<View
|
||||
style={{ height: CONTAINER_HEIGHT, justifyContent: 'center' }}
|
||||
>
|
||||
<CustomText
|
||||
fontStyle='S'
|
||||
style={{
|
||||
lineHeight: CONTAINER_HEIGHT,
|
||||
color: colors.primaryDefault
|
||||
}}
|
||||
onLayout={onLayout}
|
||||
children={t('refresh.refetch')}
|
||||
/>
|
||||
@ -299,25 +325,4 @@ const TimelineRefresh: React.FC<Props> = ({
|
||||
)
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
base: {
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
height: CONTAINER_HEIGHT * 2,
|
||||
alignItems: 'center'
|
||||
},
|
||||
container1: {
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
height: CONTAINER_HEIGHT
|
||||
},
|
||||
container2: { height: CONTAINER_HEIGHT, justifyContent: 'center' },
|
||||
explanation: {
|
||||
fontSize: StyleConstants.Font.Size.S,
|
||||
lineHeight: CONTAINER_HEIGHT
|
||||
}
|
||||
})
|
||||
|
||||
export default TimelineRefresh
|
||||
|
@ -1,6 +1,7 @@
|
||||
import analytics from '@components/analytics'
|
||||
import Icon from '@components/Icon'
|
||||
import { displayMessage } from '@components/Message'
|
||||
import CustomText from '@components/Text'
|
||||
import { useNavigation } from '@react-navigation/native'
|
||||
import { StackNavigationProp } from '@react-navigation/stack'
|
||||
import { RootStackParamList } from '@utils/navigation/navigators'
|
||||
@ -13,7 +14,7 @@ import { StyleConstants } from '@utils/styles/constants'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import React, { useCallback, useMemo } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Pressable, StyleSheet, Text, View } from 'react-native'
|
||||
import { Pressable, StyleSheet, View } from 'react-native'
|
||||
import { useQueryClient } from 'react-query'
|
||||
|
||||
export interface Props {
|
||||
@ -185,7 +186,7 @@ const TimelineActions: React.FC<Props> = ({
|
||||
size={StyleConstants.Font.Size.L}
|
||||
/>
|
||||
{status.replies_count > 0 ? (
|
||||
<Text
|
||||
<CustomText
|
||||
style={{
|
||||
color: colors.secondary,
|
||||
fontSize: StyleConstants.Font.Size.M,
|
||||
@ -193,7 +194,7 @@ const TimelineActions: React.FC<Props> = ({
|
||||
}}
|
||||
>
|
||||
{status.replies_count}
|
||||
</Text>
|
||||
</CustomText>
|
||||
) : null}
|
||||
</>
|
||||
),
|
||||
@ -213,7 +214,7 @@ const TimelineActions: React.FC<Props> = ({
|
||||
size={StyleConstants.Font.Size.L}
|
||||
/>
|
||||
{status.reblogs_count > 0 ? (
|
||||
<Text
|
||||
<CustomText
|
||||
style={{
|
||||
color: color(status.reblogged),
|
||||
fontSize: StyleConstants.Font.Size.M,
|
||||
@ -221,7 +222,7 @@ const TimelineActions: React.FC<Props> = ({
|
||||
}}
|
||||
>
|
||||
{status.reblogs_count}
|
||||
</Text>
|
||||
</CustomText>
|
||||
) : null}
|
||||
</>
|
||||
)
|
||||
@ -236,7 +237,7 @@ const TimelineActions: React.FC<Props> = ({
|
||||
size={StyleConstants.Font.Size.L}
|
||||
/>
|
||||
{status.favourites_count > 0 ? (
|
||||
<Text
|
||||
<CustomText
|
||||
style={{
|
||||
color: color(status.favourited),
|
||||
fontSize: StyleConstants.Font.Size.M,
|
||||
@ -245,7 +246,7 @@ const TimelineActions: React.FC<Props> = ({
|
||||
}}
|
||||
>
|
||||
{status.favourites_count}
|
||||
</Text>
|
||||
</CustomText>
|
||||
) : null}
|
||||
</>
|
||||
)
|
||||
@ -269,7 +270,7 @@ const TimelineActions: React.FC<Props> = ({
|
||||
: StyleConstants.Avatar.M + StyleConstants.Spacing.S
|
||||
}}
|
||||
>
|
||||
<View style={styles.actions}>
|
||||
<View style={{ flexDirection: 'row' }}>
|
||||
<Pressable
|
||||
{...(highlighted
|
||||
? {
|
||||
@ -334,9 +335,6 @@ const TimelineActions: React.FC<Props> = ({
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
actions: {
|
||||
flexDirection: 'row'
|
||||
},
|
||||
action: {
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
|
@ -1,11 +1,12 @@
|
||||
import analytics from '@components/analytics'
|
||||
import Button from '@components/Button'
|
||||
import openLink from '@components/openLink'
|
||||
import CustomText from '@components/Text'
|
||||
import { StyleConstants } from '@utils/styles/constants'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { StyleSheet, Text, View } from 'react-native'
|
||||
import { View } from 'react-native'
|
||||
import { Blurhash } from 'react-native-blurhash'
|
||||
import attachmentAspectRatio from './aspectRatio'
|
||||
|
||||
@ -27,10 +28,14 @@ const AttachmentUnsupported: React.FC<Props> = ({
|
||||
|
||||
return (
|
||||
<View
|
||||
style={[
|
||||
styles.base,
|
||||
{ aspectRatio: attachmentAspectRatio({ total, index }) }
|
||||
]}
|
||||
style={{
|
||||
flex: 1,
|
||||
flexBasis: '50%',
|
||||
padding: StyleConstants.Spacing.XS / 2,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
aspectRatio: attachmentAspectRatio({ total, index })
|
||||
}}
|
||||
>
|
||||
{attachment.blurhash ? (
|
||||
<Blurhash
|
||||
@ -44,18 +49,18 @@ const AttachmentUnsupported: React.FC<Props> = ({
|
||||
) : null}
|
||||
{!sensitiveShown ? (
|
||||
<>
|
||||
<Text
|
||||
style={[
|
||||
styles.text,
|
||||
{
|
||||
color: attachment.blurhash
|
||||
? colors.backgroundDefault
|
||||
: colors.primaryDefault
|
||||
}
|
||||
]}
|
||||
<CustomText
|
||||
fontStyle='S'
|
||||
style={{
|
||||
textAlign: 'center',
|
||||
marginBottom: StyleConstants.Spacing.S,
|
||||
color: attachment.blurhash
|
||||
? colors.backgroundDefault
|
||||
: colors.primaryDefault
|
||||
}}
|
||||
>
|
||||
{t('shared.attachment.unsupported.text')}
|
||||
</Text>
|
||||
</CustomText>
|
||||
{attachment.remote_url ? (
|
||||
<Button
|
||||
type='text'
|
||||
@ -74,19 +79,4 @@ const AttachmentUnsupported: React.FC<Props> = ({
|
||||
)
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
base: {
|
||||
flex: 1,
|
||||
flexBasis: '50%',
|
||||
padding: StyleConstants.Spacing.XS / 2,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center'
|
||||
},
|
||||
text: {
|
||||
...StyleConstants.FontStyle.S,
|
||||
textAlign: 'center',
|
||||
marginBottom: StyleConstants.Spacing.S
|
||||
}
|
||||
})
|
||||
|
||||
export default AttachmentUnsupported
|
||||
|
@ -1,11 +1,12 @@
|
||||
import analytics from '@components/analytics'
|
||||
import GracefullyImage from '@components/GracefullyImage'
|
||||
import openLink from '@components/openLink'
|
||||
import CustomText from '@components/Text'
|
||||
import { useNavigation } from '@react-navigation/native'
|
||||
import { StyleConstants } from '@utils/styles/constants'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import React from 'react'
|
||||
import { Pressable, StyleSheet, Text, View } from 'react-native'
|
||||
import { Pressable, StyleSheet, View } from 'react-native'
|
||||
|
||||
export interface Props {
|
||||
card: Pick<
|
||||
@ -22,7 +23,16 @@ const TimelineCard = React.memo(({ card }: Props) => {
|
||||
<Pressable
|
||||
accessible
|
||||
accessibilityRole='link'
|
||||
style={[styles.card, { borderColor: colors.border }]}
|
||||
style={{
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
height: StyleConstants.Font.LineHeight.M * 5,
|
||||
marginTop: StyleConstants.Spacing.M,
|
||||
borderWidth: StyleSheet.hairlineWidth,
|
||||
borderRadius: 6,
|
||||
overflow: 'hidden',
|
||||
borderColor: colors.border
|
||||
}}
|
||||
onPress={async () => {
|
||||
analytics('timeline_shared_card_press')
|
||||
await openLink(card.url, navigation)
|
||||
@ -33,71 +43,46 @@ const TimelineCard = React.memo(({ card }: Props) => {
|
||||
<GracefullyImage
|
||||
uri={{ original: card.image }}
|
||||
blurhash={card.blurhash}
|
||||
style={styles.left}
|
||||
imageStyle={styles.image}
|
||||
style={{ flexBasis: StyleConstants.Font.LineHeight.M * 5 }}
|
||||
imageStyle={{ borderTopLeftRadius: 6, borderBottomLeftRadius: 6 }}
|
||||
/>
|
||||
) : null}
|
||||
<View style={styles.right}>
|
||||
<Text
|
||||
<View style={{ flex: 1, padding: StyleConstants.Spacing.S }}>
|
||||
<CustomText
|
||||
fontStyle='S'
|
||||
numberOfLines={2}
|
||||
style={[styles.rightTitle, { color: colors.primaryDefault }]}
|
||||
style={{
|
||||
marginBottom: StyleConstants.Spacing.XS,
|
||||
fontWeight: StyleConstants.Font.Weight.Bold,
|
||||
color: colors.primaryDefault
|
||||
}}
|
||||
testID='title'
|
||||
>
|
||||
{card.title}
|
||||
</Text>
|
||||
</CustomText>
|
||||
{card.description ? (
|
||||
<Text
|
||||
<CustomText
|
||||
fontStyle='S'
|
||||
numberOfLines={1}
|
||||
style={[styles.rightDescription, { color: colors.primaryDefault }]}
|
||||
style={{
|
||||
marginBottom: StyleConstants.Spacing.XS,
|
||||
color: colors.primaryDefault
|
||||
}}
|
||||
testID='description'
|
||||
>
|
||||
{card.description}
|
||||
</Text>
|
||||
</CustomText>
|
||||
) : null}
|
||||
<Text
|
||||
<CustomText
|
||||
fontStyle='S'
|
||||
numberOfLines={1}
|
||||
style={[styles.rightLink, { color: colors.secondary }]}
|
||||
style={{ color: colors.secondary }}
|
||||
>
|
||||
{card.url}
|
||||
</Text>
|
||||
</CustomText>
|
||||
</View>
|
||||
</Pressable>
|
||||
)
|
||||
})
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
card: {
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
height: StyleConstants.Font.LineHeight.M * 5,
|
||||
marginTop: StyleConstants.Spacing.M,
|
||||
borderWidth: StyleSheet.hairlineWidth,
|
||||
borderRadius: 6,
|
||||
overflow: 'hidden'
|
||||
},
|
||||
left: {
|
||||
flexBasis: StyleConstants.Font.LineHeight.M * 5
|
||||
},
|
||||
image: {
|
||||
borderTopLeftRadius: 6,
|
||||
borderBottomLeftRadius: 6
|
||||
},
|
||||
right: {
|
||||
flex: 1,
|
||||
padding: StyleConstants.Spacing.S
|
||||
},
|
||||
rightTitle: {
|
||||
...StyleConstants.FontStyle.S,
|
||||
marginBottom: StyleConstants.Spacing.XS,
|
||||
fontWeight: StyleConstants.Font.Weight.Bold
|
||||
},
|
||||
rightDescription: {
|
||||
...StyleConstants.FontStyle.S,
|
||||
marginBottom: StyleConstants.Spacing.XS
|
||||
},
|
||||
rightLink: {
|
||||
...StyleConstants.FontStyle.S
|
||||
}
|
||||
})
|
||||
|
||||
export default TimelineCard
|
||||
|
@ -1,4 +1,5 @@
|
||||
import analytics from '@components/analytics'
|
||||
import CustomText from '@components/Text'
|
||||
import { useNavigation } from '@react-navigation/native'
|
||||
import { StackNavigationProp } from '@react-navigation/stack'
|
||||
import { TabLocalStackParamList } from '@utils/navigation/navigators'
|
||||
@ -7,7 +8,7 @@ import { StyleConstants } from '@utils/styles/constants'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { StyleSheet, Text, View } from 'react-native'
|
||||
import { StyleSheet, View } from 'react-native'
|
||||
|
||||
export interface Props {
|
||||
status: Pick<
|
||||
@ -37,7 +38,7 @@ const TimelineFeedback = React.memo(
|
||||
<View style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
|
||||
<View style={{ flexDirection: 'row' }}>
|
||||
{status.reblogs_count > 0 ? (
|
||||
<Text
|
||||
<CustomText
|
||||
accessibilityLabel={t(
|
||||
'shared.actionsUsers.reblogged_by.accessibilityLabel',
|
||||
{
|
||||
@ -64,10 +65,10 @@ const TimelineFeedback = React.memo(
|
||||
{t('shared.actionsUsers.reblogged_by.text', {
|
||||
count: status.reblogs_count
|
||||
})}
|
||||
</Text>
|
||||
</CustomText>
|
||||
) : null}
|
||||
{status.favourites_count > 0 ? (
|
||||
<Text
|
||||
<CustomText
|
||||
accessibilityLabel={t(
|
||||
'shared.actionsUsers.favourited_by.accessibilityLabel',
|
||||
{
|
||||
@ -94,12 +95,12 @@ const TimelineFeedback = React.memo(
|
||||
{t('shared.actionsUsers.favourited_by.text', {
|
||||
count: status.favourites_count
|
||||
})}
|
||||
</Text>
|
||||
</CustomText>
|
||||
) : null}
|
||||
</View>
|
||||
<View>
|
||||
{data && data.length > 1 ? (
|
||||
<Text
|
||||
<CustomText
|
||||
accessibilityLabel={t(
|
||||
'shared.actionsUsers.history.accessibilityLabel',
|
||||
{
|
||||
@ -121,7 +122,7 @@ const TimelineFeedback = React.memo(
|
||||
{t('shared.actionsUsers.history.text', {
|
||||
count: data.length - 1
|
||||
})}
|
||||
</Text>
|
||||
</CustomText>
|
||||
) : null}
|
||||
</View>
|
||||
</View>
|
||||
|
@ -1,3 +1,4 @@
|
||||
import CustomText from '@components/Text'
|
||||
import { store } from '@root/store'
|
||||
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
|
||||
import { getInstance, getInstanceAccount } from '@utils/slices/instancesSlice'
|
||||
@ -6,7 +7,7 @@ import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import htmlparser2 from 'htmlparser2-without-node-native'
|
||||
import React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Text, View } from 'react-native'
|
||||
import { View } from 'react-native'
|
||||
|
||||
const TimelineFiltered = React.memo(
|
||||
() => {
|
||||
@ -15,9 +16,9 @@ const TimelineFiltered = React.memo(
|
||||
|
||||
return (
|
||||
<View style={{ backgroundColor: colors.backgroundDefault }}>
|
||||
<Text
|
||||
<CustomText
|
||||
fontStyle='S'
|
||||
style={{
|
||||
...StyleConstants.FontStyle.S,
|
||||
color: colors.secondary,
|
||||
textAlign: 'center',
|
||||
paddingVertical: StyleConstants.Spacing.S,
|
||||
@ -25,7 +26,7 @@ const TimelineFiltered = React.memo(
|
||||
}}
|
||||
>
|
||||
{t('shared.filtered')}
|
||||
</Text>
|
||||
</CustomText>
|
||||
</View>
|
||||
)
|
||||
},
|
||||
|
@ -1,9 +1,9 @@
|
||||
import CustomText from '@components/Text'
|
||||
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
|
||||
import { StyleConstants } from '@utils/styles/constants'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Text } from 'react-native'
|
||||
|
||||
export interface Props {
|
||||
queryKey?: QueryKeyTimeline
|
||||
@ -22,15 +22,15 @@ const TimelineFullConversation = React.memo(
|
||||
status.mentions.filter(
|
||||
mention => mention.id !== status.in_reply_to_account_id
|
||||
).length) ? (
|
||||
<Text
|
||||
<CustomText
|
||||
fontStyle='S'
|
||||
style={{
|
||||
...StyleConstants.FontStyle.S,
|
||||
color: colors.blue,
|
||||
marginTop: StyleConstants.Spacing.S
|
||||
}}
|
||||
>
|
||||
{t('shared.fullConversation')}
|
||||
</Text>
|
||||
</CustomText>
|
||||
) : null
|
||||
},
|
||||
() => true
|
||||
|
@ -2,6 +2,7 @@ import analytics from '@components/analytics'
|
||||
import Icon from '@components/Icon'
|
||||
import { displayMessage } from '@components/Message'
|
||||
import { ParseEmojis } from '@components/Parse'
|
||||
import CustomText from '@components/Text'
|
||||
import {
|
||||
QueryKeyTimeline,
|
||||
useTimelineMutation
|
||||
@ -10,7 +11,7 @@ import { StyleConstants } from '@utils/styles/constants'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import React, { useCallback, useMemo } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Pressable, Text, View } from 'react-native'
|
||||
import { Pressable, View } from 'react-native'
|
||||
import { useQueryClient } from 'react-query'
|
||||
import HeaderSharedCreated from './HeaderShared/Created'
|
||||
import HeaderSharedMuted from './HeaderShared/Muted'
|
||||
@ -20,22 +21,22 @@ const Names = ({ accounts }: { accounts: Mastodon.Account[] }) => {
|
||||
const { colors } = useTheme()
|
||||
|
||||
return (
|
||||
<Text
|
||||
<CustomText
|
||||
numberOfLines={1}
|
||||
style={{ ...StyleConstants.FontStyle.M, color: colors.secondary }}
|
||||
>
|
||||
<Text>{t('shared.header.conversation.withAccounts')}</Text>
|
||||
<CustomText>{t('shared.header.conversation.withAccounts')}</CustomText>
|
||||
{accounts.map((account, index) => (
|
||||
<Text key={account.id} numberOfLines={1}>
|
||||
<CustomText key={account.id} numberOfLines={1}>
|
||||
{index !== 0 ? t('common:separator') : undefined}
|
||||
<ParseEmojis
|
||||
content={account.display_name || account.username}
|
||||
emojis={account.emojis}
|
||||
fontBold
|
||||
/>
|
||||
</Text>
|
||||
</CustomText>
|
||||
))}
|
||||
</Text>
|
||||
</CustomText>
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -1,9 +1,10 @@
|
||||
import CustomText from '@components/Text'
|
||||
import { ParseEmojis } from '@root/components/Parse'
|
||||
import { StyleConstants } from '@utils/styles/constants'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { StyleSheet, Text, View } from 'react-native'
|
||||
import { View } from 'react-native'
|
||||
|
||||
export interface Props {
|
||||
account: Mastodon.Account
|
||||
@ -16,13 +17,13 @@ const HeaderSharedAccount = React.memo(
|
||||
const { colors } = useTheme()
|
||||
|
||||
return (
|
||||
<View style={styles.base}>
|
||||
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
|
||||
{withoutName ? null : (
|
||||
<Text
|
||||
<CustomText
|
||||
accessibilityHint={t(
|
||||
'shared.header.shared.account.name.accessibilityHint'
|
||||
)}
|
||||
style={styles.name}
|
||||
style={{ marginRight: StyleConstants.Spacing.XS }}
|
||||
numberOfLines={1}
|
||||
>
|
||||
<ParseEmojis
|
||||
@ -30,34 +31,21 @@ const HeaderSharedAccount = React.memo(
|
||||
emojis={account.emojis}
|
||||
fontBold
|
||||
/>
|
||||
</Text>
|
||||
</CustomText>
|
||||
)}
|
||||
<Text
|
||||
<CustomText
|
||||
accessibilityHint={t(
|
||||
'shared.header.shared.account.account.accessibilityHint'
|
||||
)}
|
||||
style={[styles.acct, { color: colors.secondary }]}
|
||||
style={{ flexShrink: 1, color: colors.secondary }}
|
||||
numberOfLines={1}
|
||||
>
|
||||
@{account.acct}
|
||||
</Text>
|
||||
</CustomText>
|
||||
</View>
|
||||
)
|
||||
},
|
||||
() => true
|
||||
)
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
base: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center'
|
||||
},
|
||||
name: {
|
||||
marginRight: StyleConstants.Spacing.XS
|
||||
},
|
||||
acct: {
|
||||
flexShrink: 1
|
||||
}
|
||||
})
|
||||
|
||||
export default HeaderSharedAccount
|
||||
|
@ -1,10 +1,10 @@
|
||||
import analytics from '@components/analytics'
|
||||
import openLink from '@components/openLink'
|
||||
import CustomText from '@components/Text'
|
||||
import { StyleConstants } from '@utils/styles/constants'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { StyleSheet, Text } from 'react-native'
|
||||
|
||||
export interface Props {
|
||||
application?: Mastodon.Application
|
||||
@ -16,7 +16,8 @@ const HeaderSharedApplication = React.memo(
|
||||
const { t } = useTranslation('componentTimeline')
|
||||
|
||||
return application && application.name !== 'Web' ? (
|
||||
<Text
|
||||
<CustomText
|
||||
fontStyle='S'
|
||||
accessibilityRole='link'
|
||||
onPress={async () => {
|
||||
analytics('timeline_shared_header_application_press', {
|
||||
@ -24,24 +25,20 @@ const HeaderSharedApplication = React.memo(
|
||||
})
|
||||
application.website && (await openLink(application.website))
|
||||
}}
|
||||
style={[styles.application, { color: colors.secondary }]}
|
||||
style={{
|
||||
flex: 1,
|
||||
marginLeft: StyleConstants.Spacing.S,
|
||||
color: colors.secondary
|
||||
}}
|
||||
numberOfLines={1}
|
||||
>
|
||||
{t('shared.header.shared.application', {
|
||||
application: application.name
|
||||
})}
|
||||
</Text>
|
||||
</CustomText>
|
||||
) : null
|
||||
},
|
||||
() => true
|
||||
)
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
application: {
|
||||
flex: 1,
|
||||
...StyleConstants.FontStyle.S,
|
||||
marginLeft: StyleConstants.Spacing.S
|
||||
}
|
||||
})
|
||||
|
||||
export default HeaderSharedApplication
|
||||
|
@ -1,13 +1,13 @@
|
||||
import Icon from '@components/Icon'
|
||||
import RelativeTime from '@components/RelativeTime'
|
||||
import CustomText from '@components/Text'
|
||||
import { StyleConstants } from '@utils/styles/constants'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Text } from 'react-native'
|
||||
|
||||
export interface Props {
|
||||
created_at: Mastodon.Status['created_at']
|
||||
created_at: Mastodon.Status['created_at'] | number
|
||||
edited_at?: Mastodon.Status['edited_at']
|
||||
}
|
||||
|
||||
@ -18,11 +18,9 @@ const HeaderSharedCreated = React.memo(
|
||||
|
||||
return (
|
||||
<>
|
||||
<Text
|
||||
style={{ ...StyleConstants.FontStyle.S, color: colors.secondary }}
|
||||
>
|
||||
<CustomText fontStyle='S' style={{ color: colors.secondary }}>
|
||||
<RelativeTime date={edited_at || created_at} />
|
||||
</Text>
|
||||
</CustomText>
|
||||
{edited_at ? (
|
||||
<Icon
|
||||
accessibilityLabel={t(
|
||||
|
@ -5,6 +5,7 @@ import Icon from '@components/Icon'
|
||||
import { displayMessage } from '@components/Message'
|
||||
import { ParseEmojis } from '@components/Parse'
|
||||
import RelativeTime from '@components/RelativeTime'
|
||||
import CustomText from '@components/Text'
|
||||
import {
|
||||
MutationVarsTimelineUpdateStatusProperty,
|
||||
QueryKeyTimeline,
|
||||
@ -83,7 +84,7 @@ const TimelinePoll: React.FC<Props> = ({
|
||||
if (!poll.expired) {
|
||||
if (!sameAccount && !poll.voted) {
|
||||
return (
|
||||
<View style={styles.button}>
|
||||
<View style={{ marginRight: StyleConstants.Spacing.S }}>
|
||||
<Button
|
||||
onPress={() => {
|
||||
analytics('timeline_shared_vote_vote_press')
|
||||
@ -110,7 +111,7 @@ const TimelinePoll: React.FC<Props> = ({
|
||||
)
|
||||
} else {
|
||||
return (
|
||||
<View style={styles.button}>
|
||||
<View style={{ marginRight: StyleConstants.Spacing.S }}>
|
||||
<Button
|
||||
onPress={() => {
|
||||
analytics('timeline_shared_vote_refresh_press')
|
||||
@ -147,19 +148,19 @@ const TimelinePoll: React.FC<Props> = ({
|
||||
const pollExpiration = useMemo(() => {
|
||||
if (poll.expired) {
|
||||
return (
|
||||
<Text style={[styles.expiration, { color: colors.secondary }]}>
|
||||
<CustomText fontStyle='S' style={{ color: colors.secondary }}>
|
||||
{t('shared.poll.meta.expiration.expired')}
|
||||
</Text>
|
||||
</CustomText>
|
||||
)
|
||||
} else {
|
||||
if (poll.expires_at) {
|
||||
return (
|
||||
<Text style={[styles.expiration, { color: colors.secondary }]}>
|
||||
<CustomText fontStyle='S' style={{ color: colors.secondary }}>
|
||||
<Trans
|
||||
i18nKey='componentTimeline:shared.poll.meta.expiration.until'
|
||||
components={[<RelativeTime date={poll.expires_at} />]}
|
||||
/>
|
||||
</Text>
|
||||
</CustomText>
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -179,10 +180,17 @@ const TimelinePoll: React.FC<Props> = ({
|
||||
option => option.votes_count
|
||||
)?.votes_count
|
||||
return poll.options.map((option, index) => (
|
||||
<View key={index} style={styles.optionContainer}>
|
||||
<View style={styles.optionContent}>
|
||||
<View
|
||||
key={index}
|
||||
style={{ flex: 1, paddingVertical: StyleConstants.Spacing.S }}
|
||||
>
|
||||
<View style={{ flex: 1, flexDirection: 'row' }}>
|
||||
<Icon
|
||||
style={styles.optionSelection}
|
||||
style={{
|
||||
paddingTop:
|
||||
StyleConstants.Font.LineHeight.M - StyleConstants.Font.Size.M,
|
||||
marginRight: StyleConstants.Spacing.S
|
||||
}}
|
||||
name={
|
||||
`${poll.own_votes?.includes(index) ? 'Check' : ''}${
|
||||
poll.multiple ? 'Square' : 'Circle'
|
||||
@ -193,11 +201,18 @@ const TimelinePoll: React.FC<Props> = ({
|
||||
poll.own_votes?.includes(index) ? colors.blue : colors.disabled
|
||||
}
|
||||
/>
|
||||
<Text style={styles.optionText}>
|
||||
<CustomText style={{ flex: 1 }}>
|
||||
<ParseEmojis content={option.title} emojis={poll.emojis} />
|
||||
</Text>
|
||||
<Text
|
||||
style={[styles.optionPercentage, { color: colors.primaryDefault }]}
|
||||
</CustomText>
|
||||
<CustomText
|
||||
fontStyle='M'
|
||||
style={{
|
||||
alignSelf: 'center',
|
||||
marginLeft: StyleConstants.Spacing.S,
|
||||
flexBasis: '20%',
|
||||
textAlign: 'center',
|
||||
color: colors.primaryDefault
|
||||
}}
|
||||
>
|
||||
{poll.votes_count
|
||||
? Math.round(
|
||||
@ -207,21 +222,24 @@ const TimelinePoll: React.FC<Props> = ({
|
||||
)
|
||||
: 0}
|
||||
%
|
||||
</Text>
|
||||
</CustomText>
|
||||
</View>
|
||||
|
||||
<View
|
||||
style={[
|
||||
styles.background,
|
||||
{
|
||||
width: `${Math.round(
|
||||
(option.votes_count / (poll.voters_count || poll.votes_count)) *
|
||||
100
|
||||
)}%`,
|
||||
backgroundColor:
|
||||
option.votes_count === maxValue ? colors.blue : colors.disabled
|
||||
}
|
||||
]}
|
||||
style={{
|
||||
height: StyleConstants.Spacing.XS,
|
||||
minWidth: 2,
|
||||
borderTopRightRadius: 10,
|
||||
borderBottomRightRadius: 10,
|
||||
marginTop: StyleConstants.Spacing.XS,
|
||||
marginBottom: StyleConstants.Spacing.S,
|
||||
width: `${Math.round(
|
||||
(option.votes_count / (poll.voters_count || poll.votes_count)) *
|
||||
100
|
||||
)}%`,
|
||||
backgroundColor:
|
||||
option.votes_count === maxValue ? colors.blue : colors.disabled
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
))
|
||||
@ -230,7 +248,7 @@ const TimelinePoll: React.FC<Props> = ({
|
||||
return poll.options.map((option, index) => (
|
||||
<Pressable
|
||||
key={index}
|
||||
style={styles.optionContainer}
|
||||
style={{ flex: 1, paddingVertical: StyleConstants.Spacing.S }}
|
||||
onPress={() => {
|
||||
analytics('timeline_shared_vote_option_press')
|
||||
!allOptions[index] && haptics('Light')
|
||||
@ -253,16 +271,20 @@ const TimelinePoll: React.FC<Props> = ({
|
||||
}
|
||||
}}
|
||||
>
|
||||
<View style={[styles.optionContent]}>
|
||||
<View style={{ flex: 1, flexDirection: 'row' }}>
|
||||
<Icon
|
||||
style={styles.optionSelection}
|
||||
style={{
|
||||
paddingTop:
|
||||
StyleConstants.Font.LineHeight.M - StyleConstants.Font.Size.M,
|
||||
marginRight: StyleConstants.Spacing.S
|
||||
}}
|
||||
name={isSelected(index)}
|
||||
size={StyleConstants.Font.Size.M}
|
||||
color={colors.primaryDefault}
|
||||
/>
|
||||
<Text style={styles.optionText}>
|
||||
<CustomText style={{ flex: 1 }}>
|
||||
<ParseEmojis content={option.title} emojis={poll.emojis} />
|
||||
</Text>
|
||||
</CustomText>
|
||||
</View>
|
||||
</Pressable>
|
||||
))
|
||||
@ -271,25 +293,32 @@ const TimelinePoll: React.FC<Props> = ({
|
||||
const pollVoteCounts = useMemo(() => {
|
||||
if (poll.voters_count !== null) {
|
||||
return (
|
||||
<Text style={[styles.votes, { color: colors.secondary }]}>
|
||||
<CustomText fontStyle='S' style={{ color: colors.secondary }}>
|
||||
{t('shared.poll.meta.count.voters', { count: poll.voters_count })}
|
||||
{' • '}
|
||||
</Text>
|
||||
</CustomText>
|
||||
)
|
||||
} else if (poll.votes_count !== null) {
|
||||
return (
|
||||
<Text style={[styles.votes, { color: colors.secondary }]}>
|
||||
<CustomText fontStyle='S' style={{ color: colors.secondary }}>
|
||||
{t('shared.poll.meta.count.votes', { count: poll.votes_count })}
|
||||
{' • '}
|
||||
</Text>
|
||||
</CustomText>
|
||||
)
|
||||
}
|
||||
}, [poll.voters_count, poll.votes_count])
|
||||
|
||||
return (
|
||||
<View style={styles.base}>
|
||||
<View style={{ marginTop: StyleConstants.Spacing.M }}>
|
||||
{poll.expired || poll.voted ? pollBodyDisallow : pollBodyAllow}
|
||||
<View style={styles.meta}>
|
||||
<View
|
||||
style={{
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
marginTop: StyleConstants.Spacing.XS
|
||||
}}
|
||||
>
|
||||
{pollButton}
|
||||
{pollVoteCounts}
|
||||
{pollExpiration}
|
||||
@ -298,55 +327,4 @@ const TimelinePoll: React.FC<Props> = ({
|
||||
)
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
base: {
|
||||
marginTop: StyleConstants.Spacing.M
|
||||
},
|
||||
optionContainer: {
|
||||
flex: 1,
|
||||
paddingVertical: StyleConstants.Spacing.S
|
||||
},
|
||||
optionContent: {
|
||||
flex: 1,
|
||||
flexDirection: 'row'
|
||||
},
|
||||
optionText: {
|
||||
flex: 1
|
||||
},
|
||||
optionSelection: {
|
||||
paddingTop: StyleConstants.Font.LineHeight.M - StyleConstants.Font.Size.M,
|
||||
marginRight: StyleConstants.Spacing.S
|
||||
},
|
||||
optionPercentage: {
|
||||
...StyleConstants.FontStyle.M,
|
||||
alignSelf: 'center',
|
||||
marginLeft: StyleConstants.Spacing.S,
|
||||
flexBasis: '20%',
|
||||
textAlign: 'center'
|
||||
},
|
||||
background: {
|
||||
height: StyleConstants.Spacing.XS,
|
||||
minWidth: 2,
|
||||
borderTopRightRadius: 10,
|
||||
borderBottomRightRadius: 10,
|
||||
marginTop: StyleConstants.Spacing.XS,
|
||||
marginBottom: StyleConstants.Spacing.S
|
||||
},
|
||||
meta: {
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
marginTop: StyleConstants.Spacing.XS
|
||||
},
|
||||
button: {
|
||||
marginRight: StyleConstants.Spacing.S
|
||||
},
|
||||
votes: {
|
||||
...StyleConstants.FontStyle.S
|
||||
},
|
||||
expiration: {
|
||||
...StyleConstants.FontStyle.S
|
||||
}
|
||||
})
|
||||
|
||||
export default TimelinePoll
|
||||
|
@ -1,5 +1,6 @@
|
||||
import analytics from '@components/analytics'
|
||||
import { ParseHTML } from '@components/Parse'
|
||||
import CustomText from '@components/Text'
|
||||
import { useTranslateQuery } from '@utils/queryHooks/translate'
|
||||
import { getSettingsLanguage } from '@utils/slices/settingsSlice'
|
||||
import { StyleConstants } from '@utils/styles/constants'
|
||||
@ -7,7 +8,7 @@ import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import * as Localization from 'expo-localization'
|
||||
import React, { useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Pressable, Text } from 'react-native'
|
||||
import { Pressable } from 'react-native'
|
||||
import { Circle } from 'react-native-animated-spinkit'
|
||||
import { useSelector } from 'react-redux'
|
||||
|
||||
@ -85,9 +86,9 @@ const TimelineTranslate = React.memo(
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Text
|
||||
<CustomText
|
||||
fontStyle='M'
|
||||
style={{
|
||||
...StyleConstants.FontStyle.M,
|
||||
color:
|
||||
isLoading || isSuccess
|
||||
? colors.secondary
|
||||
@ -106,14 +107,14 @@ const TimelineTranslate = React.memo(
|
||||
source: data?.sourceLanguage
|
||||
})
|
||||
: t('shared.translate.default')}
|
||||
</Text>
|
||||
<Text>
|
||||
</CustomText>
|
||||
<CustomText>
|
||||
{__DEV__
|
||||
? ` Source: ${status.language}; Target: ${
|
||||
Localization.locale || settingsLanguage || 'en'
|
||||
}`
|
||||
: undefined}
|
||||
</Text>
|
||||
</CustomText>
|
||||
{isLoading ? (
|
||||
<Circle
|
||||
size={StyleConstants.Font.Size.M}
|
||||
|
Reference in New Issue
Block a user