mirror of
https://github.com/tooot-app/app
synced 2025-03-06 12:37:44 +01:00
Some translations are done
This commit is contained in:
parent
1493e20962
commit
0e3528d2cd
@ -17,6 +17,7 @@ import { themes } from 'src/utils/styles/themes'
|
|||||||
import { useTheme } from 'src/utils/styles/ThemeManager'
|
import { useTheme } from 'src/utils/styles/ThemeManager'
|
||||||
import getCurrentTab from 'src/utils/getCurrentTab'
|
import getCurrentTab from 'src/utils/getCurrentTab'
|
||||||
import { toastConfig } from 'src/components/toast'
|
import { toastConfig } from 'src/components/toast'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
|
||||||
enableScreens()
|
enableScreens()
|
||||||
const Tab = createBottomTabNavigator<RootStackParamList>()
|
const Tab = createBottomTabNavigator<RootStackParamList>()
|
||||||
@ -30,6 +31,7 @@ export type RootStackParamList = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const Index: React.FC = () => {
|
export const Index: React.FC = () => {
|
||||||
|
const { i18n } = useTranslation()
|
||||||
const { mode, theme } = useTheme()
|
const { mode, theme } = useTheme()
|
||||||
enum barStyle {
|
enum barStyle {
|
||||||
light = 'dark-content',
|
light = 'dark-content',
|
||||||
@ -39,7 +41,7 @@ export const Index: React.FC = () => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<StatusBar barStyle={barStyle[mode]} />
|
<StatusBar barStyle={barStyle[mode]} />
|
||||||
<NavigationContainer theme={themes[mode]}>
|
<NavigationContainer theme={themes[mode]} key={i18n.language}>
|
||||||
<Tab.Navigator
|
<Tab.Navigator
|
||||||
screenOptions={({ route }) => ({
|
screenOptions={({ route }) => ({
|
||||||
tabBarIcon: ({ focused, color, size }) => {
|
tabBarIcon: ({ focused, color, size }) => {
|
||||||
|
@ -11,8 +11,7 @@ import {
|
|||||||
} from 'react-native'
|
} from 'react-native'
|
||||||
import { useSafeAreaInsets } from 'react-native-safe-area-context'
|
import { useSafeAreaInsets } from 'react-native-safe-area-context'
|
||||||
import { useTheme } from 'src/utils/styles/ThemeManager'
|
import { useTheme } from 'src/utils/styles/ThemeManager'
|
||||||
|
import { StyleConstants } from 'src/utils/styles/constants'
|
||||||
import constants from 'src/utils/styles/constants'
|
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
children: React.ReactNode
|
children: React.ReactNode
|
||||||
@ -104,23 +103,23 @@ const styles = StyleSheet.create({
|
|||||||
justifyContent: 'flex-end'
|
justifyContent: 'flex-end'
|
||||||
},
|
},
|
||||||
container: {
|
container: {
|
||||||
padding: constants.SPACING_L,
|
padding: StyleConstants.Spacing.L,
|
||||||
paddingTop: constants.SPACING_M
|
paddingTop: StyleConstants.Spacing.M
|
||||||
},
|
},
|
||||||
handle: {
|
handle: {
|
||||||
alignSelf: 'center',
|
alignSelf: 'center',
|
||||||
width: constants.GLOBAL_SPACING_BASE * 8,
|
width: StyleConstants.Spacing.Global.PagePadding * 8,
|
||||||
height: constants.GLOBAL_SPACING_BASE / 2,
|
height: StyleConstants.Spacing.Global.PagePadding / 2,
|
||||||
borderRadius: 100,
|
borderRadius: 100,
|
||||||
top: -constants.SPACING_M * 2
|
top: -StyleConstants.Spacing.M * 2
|
||||||
},
|
},
|
||||||
cancel: {
|
cancel: {
|
||||||
padding: constants.SPACING_S,
|
padding: StyleConstants.Spacing.S,
|
||||||
borderWidth: 1,
|
borderWidth: 1,
|
||||||
borderRadius: 100
|
borderRadius: 100
|
||||||
},
|
},
|
||||||
text: {
|
text: {
|
||||||
fontSize: constants.FONT_SIZE_L,
|
fontSize: StyleConstants.Font.Size.L,
|
||||||
textAlign: 'center'
|
textAlign: 'center'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -2,8 +2,8 @@ import React from 'react'
|
|||||||
import { Pressable, StyleSheet, Text } from 'react-native'
|
import { Pressable, StyleSheet, Text } from 'react-native'
|
||||||
import { Feather } from '@expo/vector-icons'
|
import { Feather } from '@expo/vector-icons'
|
||||||
|
|
||||||
import constants from 'src/utils/styles/constants'
|
|
||||||
import { useTheme } from 'src/utils/styles/ThemeManager'
|
import { useTheme } from 'src/utils/styles/ThemeManager'
|
||||||
|
import { StyleConstants } from 'src/utils/styles/constants'
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
onPressFunction: () => void
|
onPressFunction: () => void
|
||||||
@ -16,7 +16,11 @@ const BottomSheetRow: React.FC<Props> = ({ onPressFunction, icon, text }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Pressable onPress={() => onPressFunction()} style={styles.pressable}>
|
<Pressable onPress={() => onPressFunction()} style={styles.pressable}>
|
||||||
<Feather name={icon} color={theme.primary} size={constants.FONT_SIZE_L} />
|
<Feather
|
||||||
|
name={icon}
|
||||||
|
color={theme.primary}
|
||||||
|
size={StyleConstants.Font.Size.L}
|
||||||
|
/>
|
||||||
<Text style={[styles.text, { color: theme.primary }]}>{text}</Text>
|
<Text style={[styles.text, { color: theme.primary }]}>{text}</Text>
|
||||||
</Pressable>
|
</Pressable>
|
||||||
)
|
)
|
||||||
@ -25,12 +29,12 @@ const BottomSheetRow: React.FC<Props> = ({ onPressFunction, icon, text }) => {
|
|||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
pressable: {
|
pressable: {
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
marginBottom: constants.SPACING_L
|
marginBottom: StyleConstants.Spacing.L
|
||||||
},
|
},
|
||||||
text: {
|
text: {
|
||||||
fontSize: constants.FONT_SIZE_M,
|
fontSize: StyleConstants.Font.Size.M,
|
||||||
lineHeight: constants.FONT_SIZE_L,
|
lineHeight: StyleConstants.Font.Size.L,
|
||||||
marginLeft: constants.SPACING_S
|
marginLeft: StyleConstants.Spacing.S
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
4
src/components/Header.tsx
Normal file
4
src/components/Header.tsx
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
import HeaderLeft from './Header/Left'
|
||||||
|
import HeaderRight from './Header/Right'
|
||||||
|
|
||||||
|
export { HeaderLeft, HeaderRight }
|
41
src/components/Header/Left.tsx
Normal file
41
src/components/Header/Left.tsx
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import { Feather } from '@expo/vector-icons'
|
||||||
|
import React from 'react'
|
||||||
|
import { Pressable, StyleSheet, Text } from 'react-native'
|
||||||
|
|
||||||
|
import { useTheme } from 'src/utils/styles/ThemeManager'
|
||||||
|
import { StyleConstants } from 'src/utils/styles/constants'
|
||||||
|
|
||||||
|
export interface Props {
|
||||||
|
onPress: () => void
|
||||||
|
text?: string
|
||||||
|
icon?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const HeaderLeft: React.FC<Props> = ({ onPress, text, icon }) => {
|
||||||
|
const { theme } = useTheme()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Pressable onPress={onPress} style={styles.base}>
|
||||||
|
{text ? (
|
||||||
|
<Text style={[styles.text, { color: theme.link }]}>{text}</Text>
|
||||||
|
) : (
|
||||||
|
<Feather
|
||||||
|
name={icon || 'chevron-left'}
|
||||||
|
color={theme.link}
|
||||||
|
size={StyleConstants.Font.Size.L}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Pressable>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
base: {
|
||||||
|
paddingRight: StyleConstants.Spacing.S
|
||||||
|
},
|
||||||
|
text: {
|
||||||
|
fontSize: StyleConstants.Font.Size.L
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
export default HeaderLeft
|
52
src/components/Header/Right.tsx
Normal file
52
src/components/Header/Right.tsx
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
import { Feather } from '@expo/vector-icons'
|
||||||
|
import React from 'react'
|
||||||
|
import { Pressable, StyleSheet, Text } from 'react-native'
|
||||||
|
|
||||||
|
import { useTheme } from 'src/utils/styles/ThemeManager'
|
||||||
|
import { StyleConstants } from 'src/utils/styles/constants'
|
||||||
|
|
||||||
|
type PropsBase = {
|
||||||
|
onPress: () => void
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PropsText extends PropsBase {
|
||||||
|
text: string
|
||||||
|
icon?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PropsIcon extends PropsBase {
|
||||||
|
text?: string
|
||||||
|
icon: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const HeaderRight: React.FC<PropsText | PropsIcon> = ({
|
||||||
|
onPress,
|
||||||
|
text,
|
||||||
|
icon
|
||||||
|
}) => {
|
||||||
|
const { theme } = useTheme()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Pressable onPress={onPress} style={styles.base}>
|
||||||
|
{text && <Text style={[styles.text, { color: theme.link }]}>{text}</Text>}
|
||||||
|
{icon && (
|
||||||
|
<Feather
|
||||||
|
name={icon}
|
||||||
|
color={theme.link}
|
||||||
|
size={StyleConstants.Font.Size.L}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Pressable>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
base: {
|
||||||
|
paddingLeft: StyleConstants.Spacing.S
|
||||||
|
},
|
||||||
|
text: {
|
||||||
|
fontSize: StyleConstants.Font.Size.L
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
export default HeaderRight
|
@ -9,8 +9,7 @@ import {
|
|||||||
View
|
View
|
||||||
} from 'react-native'
|
} from 'react-native'
|
||||||
import { useTheme } from 'src/utils/styles/ThemeManager'
|
import { useTheme } from 'src/utils/styles/ThemeManager'
|
||||||
|
import { StyleConstants } from 'src/utils/styles/constants'
|
||||||
import constants from 'src/utils/styles/constants'
|
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
text: string
|
text: string
|
||||||
@ -66,8 +65,8 @@ const styles = StyleSheet.create({
|
|||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
paddingLeft: constants.GLOBAL_PAGE_PADDING,
|
paddingLeft: StyleConstants.Spacing.Global.PagePadding,
|
||||||
paddingRight: constants.GLOBAL_PAGE_PADDING
|
paddingRight: StyleConstants.Spacing.Global.PagePadding
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { StyleSheet, View } from 'react-native'
|
import { StyleSheet, View } from 'react-native'
|
||||||
import { useTheme } from 'src/utils/styles/ThemeManager'
|
import { useTheme } from 'src/utils/styles/ThemeManager'
|
||||||
|
import { StyleConstants } from 'src/utils/styles/constants'
|
||||||
import constants from 'src/utils/styles/constants'
|
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
children: React.ReactNode
|
children: React.ReactNode
|
||||||
@ -18,7 +17,9 @@ const MenuContainer: React.FC<Props> = ({ ...props }) => {
|
|||||||
styles.base,
|
styles.base,
|
||||||
{
|
{
|
||||||
borderTopColor: theme.separator,
|
borderTopColor: theme.separator,
|
||||||
marginTop: props.marginTop ? constants.GLOBAL_PAGE_PADDING : 0
|
marginTop: props.marginTop
|
||||||
|
? StyleConstants.Spacing.Global.PagePadding
|
||||||
|
: 0
|
||||||
}
|
}
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
@ -30,7 +31,7 @@ const MenuContainer: React.FC<Props> = ({ ...props }) => {
|
|||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
base: {
|
base: {
|
||||||
borderTopWidth: 1,
|
borderTopWidth: 1,
|
||||||
marginBottom: constants.GLOBAL_PAGE_PADDING
|
marginBottom: StyleConstants.Spacing.Global.PagePadding
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -3,8 +3,8 @@ import { Pressable, StyleSheet, Text, View } from 'react-native'
|
|||||||
import { Feather } from '@expo/vector-icons'
|
import { Feather } from '@expo/vector-icons'
|
||||||
import { useTheme } from 'src/utils/styles/ThemeManager'
|
import { useTheme } from 'src/utils/styles/ThemeManager'
|
||||||
|
|
||||||
import constants from 'src/utils/styles/constants'
|
|
||||||
import { ColorDefinitions } from 'src/utils/styles/themes'
|
import { ColorDefinitions } from 'src/utils/styles/themes'
|
||||||
|
import { StyleConstants } from 'src/utils/styles/constants'
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
iconFront?: string
|
iconFront?: string
|
||||||
@ -34,7 +34,7 @@ const Core: React.FC<Props> = ({
|
|||||||
{iconFront && (
|
{iconFront && (
|
||||||
<Feather
|
<Feather
|
||||||
name={iconFront}
|
name={iconFront}
|
||||||
size={constants.FONT_SIZE_M + 2}
|
size={StyleConstants.Font.Size.M + 2}
|
||||||
color={theme[iconFrontColor]}
|
color={theme[iconFrontColor]}
|
||||||
style={styles.iconFront}
|
style={styles.iconFront}
|
||||||
/>
|
/>
|
||||||
@ -55,7 +55,7 @@ const Core: React.FC<Props> = ({
|
|||||||
{iconBack && (
|
{iconBack && (
|
||||||
<Feather
|
<Feather
|
||||||
name={iconBack}
|
name={iconBack}
|
||||||
size={constants.FONT_SIZE_M + 2}
|
size={StyleConstants.Font.Size.M + 2}
|
||||||
color={theme[iconBackColor]}
|
color={theme[iconBackColor]}
|
||||||
style={styles.iconBack}
|
style={styles.iconBack}
|
||||||
/>
|
/>
|
||||||
@ -90,8 +90,8 @@ const styles = StyleSheet.create({
|
|||||||
core: {
|
core: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
paddingLeft: constants.GLOBAL_PAGE_PADDING,
|
paddingLeft: StyleConstants.Spacing.Global.PagePadding,
|
||||||
paddingRight: constants.GLOBAL_PAGE_PADDING
|
paddingRight: StyleConstants.Spacing.Global.PagePadding
|
||||||
},
|
},
|
||||||
front: {
|
front: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
@ -108,10 +108,10 @@ const styles = StyleSheet.create({
|
|||||||
marginRight: 8
|
marginRight: 8
|
||||||
},
|
},
|
||||||
text: {
|
text: {
|
||||||
fontSize: constants.FONT_SIZE_M
|
fontSize: StyleConstants.Font.Size.M
|
||||||
},
|
},
|
||||||
content: {
|
content: {
|
||||||
fontSize: constants.FONT_SIZE_M
|
fontSize: StyleConstants.Font.Size.M
|
||||||
},
|
},
|
||||||
iconBack: {
|
iconBack: {
|
||||||
marginLeft: 8
|
marginLeft: 8
|
||||||
|
3
src/components/NetworkState.tsx
Normal file
3
src/components/NetworkState.tsx
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import NetworkStateError from './NetworkState/Error'
|
||||||
|
|
||||||
|
export { NetworkStateError }
|
20
src/components/NetworkState/Error.tsx
Normal file
20
src/components/NetworkState/Error.tsx
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import { StyleSheet, Text, View } from 'react-native'
|
||||||
|
|
||||||
|
const NetworkStateError = () => {
|
||||||
|
return (
|
||||||
|
<View style={styles.base}>
|
||||||
|
<Text>加载错误</Text>
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
base: {
|
||||||
|
flex: 1,
|
||||||
|
// justifyContent: 'center',
|
||||||
|
alignItems: 'center'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
export default NetworkStateError
|
@ -5,8 +5,7 @@ import { useNavigation } from '@react-navigation/native'
|
|||||||
import Avatar from './Shared/Avatar'
|
import Avatar from './Shared/Avatar'
|
||||||
import HeaderConversation from './Shared/HeaderConversation'
|
import HeaderConversation from './Shared/HeaderConversation'
|
||||||
import Content from './Shared/Content'
|
import Content from './Shared/Content'
|
||||||
|
import { StyleConstants } from 'src/utils/styles/constants'
|
||||||
import constants from 'src/utils/styles/constants'
|
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
item: Mastodon.Conversation
|
item: Mastodon.Conversation
|
||||||
@ -60,7 +59,7 @@ const styles = StyleSheet.create({
|
|||||||
statusView: {
|
statusView: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
padding: constants.GLOBAL_PAGE_PADDING
|
padding: StyleConstants.Spacing.Global.PagePadding
|
||||||
},
|
},
|
||||||
status: {
|
status: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
|
@ -10,8 +10,7 @@ import Poll from './Shared/Poll'
|
|||||||
import Attachment from './Shared/Attachment'
|
import Attachment from './Shared/Attachment'
|
||||||
import Card from './Shared/Card'
|
import Card from './Shared/Card'
|
||||||
import ActionsStatus from './Shared/ActionsStatus'
|
import ActionsStatus from './Shared/ActionsStatus'
|
||||||
|
import { StyleConstants } from 'src/utils/styles/constants'
|
||||||
import constants from 'src/utils/styles/constants'
|
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
item: Mastodon.Status
|
item: Mastodon.Status
|
||||||
@ -51,7 +50,7 @@ const TimelineDefault: React.FC<Props> = ({ item, queryKey }) => {
|
|||||||
media_attachments={actualStatus.media_attachments}
|
media_attachments={actualStatus.media_attachments}
|
||||||
sensitive={actualStatus.sensitive}
|
sensitive={actualStatus.sensitive}
|
||||||
width={
|
width={
|
||||||
Dimensions.get('window').width - constants.SPACING_M * 2 - 50 - 8
|
Dimensions.get('window').width - StyleConstants.Spacing.M * 2 - 50 - 8
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
@ -107,7 +106,7 @@ const styles = StyleSheet.create({
|
|||||||
statusView: {
|
statusView: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
padding: constants.GLOBAL_PAGE_PADDING
|
padding: StyleConstants.Spacing.Global.PagePadding
|
||||||
},
|
},
|
||||||
status: {
|
status: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
|
@ -10,8 +10,7 @@ import Poll from './Shared/Poll'
|
|||||||
import Attachment from './Shared/Attachment'
|
import Attachment from './Shared/Attachment'
|
||||||
import Card from './Shared/Card'
|
import Card from './Shared/Card'
|
||||||
import ActionsStatus from './Shared/ActionsStatus'
|
import ActionsStatus from './Shared/ActionsStatus'
|
||||||
|
import { StyleConstants } from 'src/utils/styles/constants'
|
||||||
import constants from 'src/utils/styles/constants'
|
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
notification: Mastodon.Notification
|
notification: Mastodon.Notification
|
||||||
@ -98,7 +97,7 @@ const styles = StyleSheet.create({
|
|||||||
notificationView: {
|
notificationView: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
padding: constants.GLOBAL_PAGE_PADDING
|
padding: StyleConstants.Spacing.Global.PagePadding
|
||||||
},
|
},
|
||||||
notification: {
|
notification: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { StyleSheet, View } from 'react-native'
|
import { StyleSheet, View } from 'react-native'
|
||||||
|
|
||||||
import constants from 'src/utils/styles/constants'
|
|
||||||
import { useTheme } from 'src/utils/styles/ThemeManager'
|
import { useTheme } from 'src/utils/styles/ThemeManager'
|
||||||
|
import { StyleConstants } from 'src/utils/styles/constants'
|
||||||
|
|
||||||
const TimelineSeparator = () => {
|
const TimelineSeparator = () => {
|
||||||
const { theme } = useTheme()
|
const { theme } = useTheme()
|
||||||
@ -13,8 +13,11 @@ const TimelineSeparator = () => {
|
|||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
base: {
|
base: {
|
||||||
borderTopWidth: 1,
|
borderTopWidth: 1,
|
||||||
marginLeft: constants.SPACING_M + constants.AVATAR_S + constants.SPACING_S,
|
marginLeft:
|
||||||
marginRight: constants.SPACING_M
|
StyleConstants.Spacing.M +
|
||||||
|
StyleConstants.Avatar.S +
|
||||||
|
StyleConstants.Spacing.S,
|
||||||
|
marginRight: StyleConstants.Spacing.M
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -4,8 +4,7 @@ import { Feather } from '@expo/vector-icons'
|
|||||||
|
|
||||||
import Emojis from './Emojis'
|
import Emojis from './Emojis'
|
||||||
import { useTheme } from 'src/utils/styles/ThemeManager'
|
import { useTheme } from 'src/utils/styles/ThemeManager'
|
||||||
|
import { StyleConstants } from 'src/utils/styles/constants'
|
||||||
import constants from 'src/utils/styles/constants'
|
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
action: 'favourite' | 'follow' | 'mention' | 'poll' | 'reblog'
|
action: 'favourite' | 'follow' | 'mention' | 'poll' | 'reblog'
|
||||||
@ -30,7 +29,7 @@ const Actioned: React.FC<Props> = ({
|
|||||||
icon = (
|
icon = (
|
||||||
<Feather
|
<Feather
|
||||||
name='heart'
|
name='heart'
|
||||||
size={constants.FONT_SIZE_S}
|
size={StyleConstants.Font.Size.S}
|
||||||
color={iconColor}
|
color={iconColor}
|
||||||
style={styles.icon}
|
style={styles.icon}
|
||||||
/>
|
/>
|
||||||
@ -41,7 +40,7 @@ const Actioned: React.FC<Props> = ({
|
|||||||
icon = (
|
icon = (
|
||||||
<Feather
|
<Feather
|
||||||
name='user-plus'
|
name='user-plus'
|
||||||
size={constants.FONT_SIZE_S}
|
size={StyleConstants.Font.Size.S}
|
||||||
color={iconColor}
|
color={iconColor}
|
||||||
style={styles.icon}
|
style={styles.icon}
|
||||||
/>
|
/>
|
||||||
@ -52,7 +51,7 @@ const Actioned: React.FC<Props> = ({
|
|||||||
icon = (
|
icon = (
|
||||||
<Feather
|
<Feather
|
||||||
name='bar-chart-2'
|
name='bar-chart-2'
|
||||||
size={constants.FONT_SIZE_S}
|
size={StyleConstants.Font.Size.S}
|
||||||
color='black'
|
color='black'
|
||||||
style={styles.icon}
|
style={styles.icon}
|
||||||
/>
|
/>
|
||||||
@ -63,7 +62,7 @@ const Actioned: React.FC<Props> = ({
|
|||||||
icon = (
|
icon = (
|
||||||
<Feather
|
<Feather
|
||||||
name='repeat'
|
name='repeat'
|
||||||
size={constants.FONT_SIZE_S}
|
size={StyleConstants.Font.Size.S}
|
||||||
color={iconColor}
|
color={iconColor}
|
||||||
style={styles.icon}
|
style={styles.icon}
|
||||||
/>
|
/>
|
||||||
@ -81,7 +80,7 @@ const Actioned: React.FC<Props> = ({
|
|||||||
<Emojis
|
<Emojis
|
||||||
content={content}
|
content={content}
|
||||||
emojis={emojis}
|
emojis={emojis}
|
||||||
size={constants.FONT_SIZE_S}
|
size={StyleConstants.Font.Size.S}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<Text>{content}</Text>
|
<Text>{content}</Text>
|
||||||
@ -97,11 +96,11 @@ const Actioned: React.FC<Props> = ({
|
|||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
actioned: {
|
actioned: {
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
marginBottom: constants.SPACING_S
|
marginBottom: StyleConstants.Spacing.S
|
||||||
},
|
},
|
||||||
icon: {
|
icon: {
|
||||||
marginLeft: constants.AVATAR_S - constants.FONT_SIZE_S,
|
marginLeft: StyleConstants.Avatar.S - StyleConstants.Font.Size.S,
|
||||||
marginRight: constants.SPACING_S
|
marginRight: StyleConstants.Spacing.S
|
||||||
},
|
},
|
||||||
content: {
|
content: {
|
||||||
flexDirection: 'row'
|
flexDirection: 'row'
|
||||||
|
@ -14,9 +14,9 @@ import { Feather } from '@expo/vector-icons'
|
|||||||
import client from 'src/api/client'
|
import client from 'src/api/client'
|
||||||
import { getLocalAccountId } from 'src/utils/slices/instancesSlice'
|
import { getLocalAccountId } from 'src/utils/slices/instancesSlice'
|
||||||
import { useTheme } from 'src/utils/styles/ThemeManager'
|
import { useTheme } from 'src/utils/styles/ThemeManager'
|
||||||
import constants from 'src/utils/styles/constants'
|
|
||||||
import { toast } from 'src/components/toast'
|
import { toast } from 'src/components/toast'
|
||||||
import { useSelector } from 'react-redux'
|
import { useSelector } from 'react-redux'
|
||||||
|
import { StyleConstants } from 'src/utils/styles/constants'
|
||||||
|
|
||||||
const fireMutation = async ({
|
const fireMutation = async ({
|
||||||
id,
|
id,
|
||||||
@ -175,14 +175,14 @@ const ActionsStatus: React.FC<Props> = ({ queryKey, status }) => {
|
|||||||
<Feather
|
<Feather
|
||||||
name='message-circle'
|
name='message-circle'
|
||||||
color={iconColor}
|
color={iconColor}
|
||||||
size={constants.FONT_SIZE_M + 2}
|
size={StyleConstants.Font.Size.M + 2}
|
||||||
/>
|
/>
|
||||||
{status.replies_count > 0 && (
|
{status.replies_count > 0 && (
|
||||||
<Text
|
<Text
|
||||||
style={{
|
style={{
|
||||||
color: theme.secondary,
|
color: theme.secondary,
|
||||||
fontSize: constants.FONT_SIZE_M,
|
fontSize: StyleConstants.Font.Size.M,
|
||||||
marginLeft: constants.SPACING_XS
|
marginLeft: StyleConstants.Spacing.XS
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{status.replies_count}
|
{status.replies_count}
|
||||||
@ -201,7 +201,7 @@ const ActionsStatus: React.FC<Props> = ({ queryKey, status }) => {
|
|||||||
? iconColorAction(status.reblogged)
|
? iconColorAction(status.reblogged)
|
||||||
: theme.disabled
|
: theme.disabled
|
||||||
}
|
}
|
||||||
size={constants.FONT_SIZE_M + 2}
|
size={StyleConstants.Font.Size.M + 2}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
[status.reblogged]
|
[status.reblogged]
|
||||||
@ -211,7 +211,7 @@ const ActionsStatus: React.FC<Props> = ({ queryKey, status }) => {
|
|||||||
<Feather
|
<Feather
|
||||||
name='heart'
|
name='heart'
|
||||||
color={iconColorAction(status.favourited)}
|
color={iconColorAction(status.favourited)}
|
||||||
size={constants.FONT_SIZE_M + 2}
|
size={StyleConstants.Font.Size.M + 2}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
[status.favourited]
|
[status.favourited]
|
||||||
@ -221,7 +221,7 @@ const ActionsStatus: React.FC<Props> = ({ queryKey, status }) => {
|
|||||||
<Feather
|
<Feather
|
||||||
name='bookmark'
|
name='bookmark'
|
||||||
color={iconColorAction(status.bookmarked)}
|
color={iconColorAction(status.bookmarked)}
|
||||||
size={constants.FONT_SIZE_M + 2}
|
size={StyleConstants.Font.Size.M + 2}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
[status.bookmarked]
|
[status.bookmarked]
|
||||||
@ -231,7 +231,7 @@ const ActionsStatus: React.FC<Props> = ({ queryKey, status }) => {
|
|||||||
<Feather
|
<Feather
|
||||||
name='share-2'
|
name='share-2'
|
||||||
color={iconColor}
|
color={iconColor}
|
||||||
size={constants.FONT_SIZE_M + 2}
|
size={StyleConstants.Font.Size.M + 2}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
[]
|
[]
|
||||||
@ -374,7 +374,7 @@ const styles = StyleSheet.create({
|
|||||||
width: '100%',
|
width: '100%',
|
||||||
flex: 1,
|
flex: 1,
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
marginTop: constants.SPACING_M
|
marginTop: StyleConstants.Spacing.M
|
||||||
},
|
},
|
||||||
action: {
|
action: {
|
||||||
width: '20%',
|
width: '20%',
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import React, { useCallback } from 'react'
|
import React, { useCallback } from 'react'
|
||||||
import { Image, Pressable, StyleSheet } from 'react-native'
|
import { Image, Pressable, StyleSheet } from 'react-native'
|
||||||
import { useNavigation } from '@react-navigation/native'
|
import { useNavigation } from '@react-navigation/native'
|
||||||
|
import { StyleConstants } from 'src/utils/styles/constants'
|
||||||
import constants from 'src/utils/styles/constants'
|
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
uri: string
|
uri: string
|
||||||
@ -27,9 +26,9 @@ const Avatar: React.FC<Props> = ({ uri, id }) => {
|
|||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
avatar: {
|
avatar: {
|
||||||
width: constants.AVATAR_S,
|
width: StyleConstants.Avatar.S,
|
||||||
height: constants.AVATAR_S,
|
height: StyleConstants.Avatar.S,
|
||||||
marginRight: constants.SPACING_S
|
marginRight: StyleConstants.Spacing.S
|
||||||
},
|
},
|
||||||
image: {
|
image: {
|
||||||
width: '100%',
|
width: '100%',
|
||||||
|
@ -4,8 +4,8 @@ import Collapsible from 'react-native-collapsible'
|
|||||||
|
|
||||||
import ParseContent from 'src/components/ParseContent'
|
import ParseContent from 'src/components/ParseContent'
|
||||||
|
|
||||||
import constants from 'src/utils/styles/constants'
|
|
||||||
import { useTheme } from 'src/utils/styles/ThemeManager'
|
import { useTheme } from 'src/utils/styles/ThemeManager'
|
||||||
|
import { StyleConstants } from 'src/utils/styles/constants'
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
content: string
|
content: string
|
||||||
@ -40,7 +40,7 @@ const Content: React.FC<Props> = ({
|
|||||||
<Collapsible collapsed={spoilerCollapsed}>
|
<Collapsible collapsed={spoilerCollapsed}>
|
||||||
<ParseContent
|
<ParseContent
|
||||||
content={content}
|
content={content}
|
||||||
size={constants.FONT_SIZE_M}
|
size={StyleConstants.Font.Size.M}
|
||||||
emojis={emojis}
|
emojis={emojis}
|
||||||
mentions={mentions}
|
mentions={mentions}
|
||||||
/>
|
/>
|
||||||
@ -49,7 +49,7 @@ const Content: React.FC<Props> = ({
|
|||||||
) : (
|
) : (
|
||||||
<ParseContent
|
<ParseContent
|
||||||
content={content}
|
content={content}
|
||||||
size={constants.FONT_SIZE_M}
|
size={StyleConstants.Font.Size.M}
|
||||||
emojis={emojis}
|
emojis={emojis}
|
||||||
mentions={mentions}
|
mentions={mentions}
|
||||||
/>
|
/>
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { Image, StyleSheet, Text } from 'react-native'
|
import { Image, StyleSheet, Text } from 'react-native'
|
||||||
import { useTheme } from 'src/utils/styles/ThemeManager'
|
import { useTheme } from 'src/utils/styles/ThemeManager'
|
||||||
|
import { StyleConstants } from 'src/utils/styles/constants'
|
||||||
import constants from 'src/utils/styles/constants'
|
|
||||||
|
|
||||||
const regexEmoji = new RegExp(/(:[a-z0-9_]+:)/)
|
const regexEmoji = new RegExp(/(:[a-z0-9_]+:)/)
|
||||||
|
|
||||||
@ -25,7 +24,7 @@ const Emojis: React.FC<Props> = ({
|
|||||||
fontSize: size,
|
fontSize: size,
|
||||||
lineHeight: size + 2,
|
lineHeight: size + 2,
|
||||||
color: theme.primary,
|
color: theme.primary,
|
||||||
...(fontBold && { fontWeight: constants.FONT_WEIGHT_BOLD })
|
...(fontBold && { fontWeight: StyleConstants.Font.Weight.Bold })
|
||||||
},
|
},
|
||||||
image: {
|
image: {
|
||||||
width: size,
|
width: size,
|
||||||
|
@ -9,11 +9,11 @@ import relativeTime from 'src/utils/relativeTime'
|
|||||||
import client from 'src/api/client'
|
import client from 'src/api/client'
|
||||||
import { getLocalAccountId, getLocalUrl } from 'src/utils/slices/instancesSlice'
|
import { getLocalAccountId, getLocalUrl } from 'src/utils/slices/instancesSlice'
|
||||||
import { useTheme } from 'src/utils/styles/ThemeManager'
|
import { useTheme } from 'src/utils/styles/ThemeManager'
|
||||||
import constants from 'src/utils/styles/constants'
|
|
||||||
import BottomSheet from 'src/components/BottomSheet'
|
import BottomSheet from 'src/components/BottomSheet'
|
||||||
import BottomSheetRow from 'src/components/BottomSheet/Row'
|
import BottomSheetRow from 'src/components/BottomSheet/Row'
|
||||||
import { toast } from 'src/components/toast'
|
import { toast } from 'src/components/toast'
|
||||||
import { useSelector } from 'react-redux'
|
import { useSelector } from 'react-redux'
|
||||||
|
import { StyleConstants } from 'src/utils/styles/constants'
|
||||||
|
|
||||||
const fireMutation = async ({
|
const fireMutation = async ({
|
||||||
id,
|
id,
|
||||||
@ -156,7 +156,7 @@ const HeaderDefault: React.FC<Props> = ({
|
|||||||
<Feather
|
<Feather
|
||||||
name='more-horizontal'
|
name='more-horizontal'
|
||||||
color={theme.secondary}
|
color={theme.secondary}
|
||||||
size={constants.FONT_SIZE_M + 2}
|
size={StyleConstants.Font.Size.M + 2}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
[]
|
[]
|
||||||
@ -170,7 +170,7 @@ const HeaderDefault: React.FC<Props> = ({
|
|||||||
<Emojis
|
<Emojis
|
||||||
content={name}
|
content={name}
|
||||||
emojis={emojis}
|
emojis={emojis}
|
||||||
size={constants.FONT_SIZE_M}
|
size={StyleConstants.Font.Size.M}
|
||||||
fontBold={true}
|
fontBold={true}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
@ -202,7 +202,7 @@ const HeaderDefault: React.FC<Props> = ({
|
|||||||
{visibility === 'private' && (
|
{visibility === 'private' && (
|
||||||
<Feather
|
<Feather
|
||||||
name='lock'
|
name='lock'
|
||||||
size={constants.FONT_SIZE_S}
|
size={StyleConstants.Font.Size.S}
|
||||||
color={theme.secondary}
|
color={theme.secondary}
|
||||||
style={styles.visibility}
|
style={styles.visibility}
|
||||||
/>
|
/>
|
||||||
@ -297,24 +297,24 @@ const styles = StyleSheet.create({
|
|||||||
},
|
},
|
||||||
account: {
|
account: {
|
||||||
flexShrink: 1,
|
flexShrink: 1,
|
||||||
marginLeft: constants.SPACING_XS,
|
marginLeft: StyleConstants.Spacing.XS,
|
||||||
lineHeight: constants.FONT_SIZE_M + 2
|
lineHeight: StyleConstants.Font.Size.M + 2
|
||||||
},
|
},
|
||||||
meta: {
|
meta: {
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
marginTop: constants.SPACING_XS,
|
marginTop: StyleConstants.Spacing.XS,
|
||||||
marginBottom: constants.SPACING_S
|
marginBottom: StyleConstants.Spacing.S
|
||||||
},
|
},
|
||||||
created_at: {
|
created_at: {
|
||||||
fontSize: constants.FONT_SIZE_S
|
fontSize: StyleConstants.Font.Size.S
|
||||||
},
|
},
|
||||||
visibility: {
|
visibility: {
|
||||||
marginLeft: constants.SPACING_S
|
marginLeft: StyleConstants.Spacing.S
|
||||||
},
|
},
|
||||||
application: {
|
application: {
|
||||||
fontSize: constants.FONT_SIZE_S,
|
fontSize: StyleConstants.Font.Size.S,
|
||||||
marginLeft: constants.SPACING_S
|
marginLeft: StyleConstants.Spacing.S
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -3,8 +3,8 @@ import { StyleSheet, Text, View } from 'react-native'
|
|||||||
import { SafeAreaView } from 'react-native-safe-area-context'
|
import { SafeAreaView } from 'react-native-safe-area-context'
|
||||||
import Toast from 'react-native-toast-message'
|
import Toast from 'react-native-toast-message'
|
||||||
import { useTheme } from 'src/utils/styles/ThemeManager'
|
import { useTheme } from 'src/utils/styles/ThemeManager'
|
||||||
import constants from 'src/utils/styles/constants'
|
|
||||||
import { Feather } from '@expo/vector-icons'
|
import { Feather } from '@expo/vector-icons'
|
||||||
|
import { StyleConstants } from 'src/utils/styles/constants'
|
||||||
|
|
||||||
export interface Params {
|
export interface Params {
|
||||||
type: 'success' | 'error' | 'warning'
|
type: 'success' | 'error' | 'warning'
|
||||||
@ -65,7 +65,7 @@ const ToastBase = ({ config }: { config: Config }) => {
|
|||||||
<Feather
|
<Feather
|
||||||
name={iconSet[config.type]}
|
name={iconSet[config.type]}
|
||||||
color={theme[config.type]}
|
color={theme[config.type]}
|
||||||
size={constants.FONT_SIZE_M + 2}
|
size={StyleConstants.Font.Size.M + 2}
|
||||||
/>
|
/>
|
||||||
<Text style={[styles.text, { color: theme.primary }]}>
|
<Text style={[styles.text, { color: theme.primary }]}>
|
||||||
{config.text1}
|
{config.text1}
|
||||||
@ -91,11 +91,11 @@ const styles = StyleSheet.create({
|
|||||||
flex: 1,
|
flex: 1,
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
padding: constants.SPACING_M
|
padding: StyleConstants.Spacing.M
|
||||||
},
|
},
|
||||||
text: {
|
text: {
|
||||||
fontSize: constants.FONT_SIZE_M,
|
fontSize: StyleConstants.Font.Size.M,
|
||||||
marginLeft: constants.SPACING_S
|
marginLeft: StyleConstants.Spacing.S
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -1,11 +1,21 @@
|
|||||||
export default {
|
export default {
|
||||||
common: require('./common').default,
|
common: require('./common').default,
|
||||||
|
|
||||||
|
local: require('./screens/local').default,
|
||||||
|
|
||||||
|
public: require('./screens/public').default,
|
||||||
|
|
||||||
|
notifications: require('./screens/notifications').default,
|
||||||
|
|
||||||
meRoot: require('./screens/meRoot').default,
|
meRoot: require('./screens/meRoot').default,
|
||||||
meConversations: require('./screens/meConversations').default,
|
meConversations: require('./screens/meConversations').default,
|
||||||
meBookmarks: require('./screens/meBookmarks').default,
|
meBookmarks: require('./screens/meBookmarks').default,
|
||||||
meFavourites: require('./screens/meFavourites').default,
|
meFavourites: require('./screens/meFavourites').default,
|
||||||
meLists: require('./screens/meLists').default,
|
meLists: require('./screens/meLists').default,
|
||||||
meListsList: require('./screens/meListsList').default,
|
meListsList: require('./screens/meListsList').default,
|
||||||
meSettings: require('./screens/meSettings').default
|
meSettings: require('./screens/meSettings').default,
|
||||||
|
|
||||||
|
sharedAccount: require('./screens/sharedAccount').default,
|
||||||
|
sharedToot: require('./screens/sharedToot').default,
|
||||||
|
sharedWebview: require('./screens/sharedWebview').default
|
||||||
}
|
}
|
||||||
|
@ -1,20 +1,5 @@
|
|||||||
export default {
|
export default {
|
||||||
buttons: {
|
buttons: {
|
||||||
cancel: '取消'
|
cancel: '取消'
|
||||||
},
|
|
||||||
headers: {
|
|
||||||
local: {
|
|
||||||
segments: {
|
|
||||||
left: '我的关注',
|
|
||||||
right: '本站嘟嘟'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
public: {
|
|
||||||
segments: {
|
|
||||||
left: '跨站关注',
|
|
||||||
right: '外站嘟嘟'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
notifications: '我的通知'
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
9
src/i18n/zh/screens/local.ts
Normal file
9
src/i18n/zh/screens/local.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
export default {
|
||||||
|
heading: {
|
||||||
|
segments: {
|
||||||
|
left: '我的关注',
|
||||||
|
right: '本站嘟嘟'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
content: {}
|
||||||
|
}
|
@ -1,7 +1,12 @@
|
|||||||
export default {
|
export default {
|
||||||
heading: '我的长毛象',
|
heading: '我的长毛象',
|
||||||
content: {
|
content: {
|
||||||
login: {},
|
login: {
|
||||||
|
server: {
|
||||||
|
placeholder: '请输入服务器'
|
||||||
|
},
|
||||||
|
button: '登录'
|
||||||
|
},
|
||||||
collections: {
|
collections: {
|
||||||
conversations: '$t(meConversations:heading)',
|
conversations: '$t(meConversations:heading)',
|
||||||
bookmarks: '$t(meBookmarks:heading)',
|
bookmarks: '$t(meBookmarks:heading)',
|
||||||
|
@ -10,7 +10,7 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
theme: {
|
theme: {
|
||||||
heading: '颜色模式',
|
heading: '应用外观',
|
||||||
options: {
|
options: {
|
||||||
auto: '跟随系统',
|
auto: '跟随系统',
|
||||||
light: '浅色模式',
|
light: '浅色模式',
|
||||||
|
4
src/i18n/zh/screens/notifications.ts
Normal file
4
src/i18n/zh/screens/notifications.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
export default {
|
||||||
|
heading: '通知',
|
||||||
|
content: {}
|
||||||
|
}
|
9
src/i18n/zh/screens/public.ts
Normal file
9
src/i18n/zh/screens/public.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
export default {
|
||||||
|
heading: {
|
||||||
|
segments: {
|
||||||
|
left: '跨站关注',
|
||||||
|
right: '外站嘟嘟'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
content: {}
|
||||||
|
}
|
19
src/i18n/zh/screens/sharedAccount.ts
Normal file
19
src/i18n/zh/screens/sharedAccount.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
export default {
|
||||||
|
heading: {
|
||||||
|
loading: '加载中…',
|
||||||
|
error: '加载错误'
|
||||||
|
},
|
||||||
|
content: {
|
||||||
|
created_at: '加入时间:{{date}}',
|
||||||
|
summary: {
|
||||||
|
statuses_count: '{{count}} 条嘟文',
|
||||||
|
followers_count: '关注 {{count}} 人',
|
||||||
|
following_count: '被 {{count}} 人关注'
|
||||||
|
},
|
||||||
|
segments: {
|
||||||
|
left: '所有嘟嘟',
|
||||||
|
middle: '嘟嘟和回复',
|
||||||
|
right: '所有媒体'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
4
src/i18n/zh/screens/sharedToot.ts
Normal file
4
src/i18n/zh/screens/sharedToot.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
export default {
|
||||||
|
heading: '对话',
|
||||||
|
content: {}
|
||||||
|
}
|
7
src/i18n/zh/screens/sharedWebview.ts
Normal file
7
src/i18n/zh/screens/sharedWebview.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
export default {
|
||||||
|
heading: {
|
||||||
|
loading: '加载中…',
|
||||||
|
error: '加载错误'
|
||||||
|
},
|
||||||
|
content: {}
|
||||||
|
}
|
@ -10,8 +10,8 @@ const ScreenLocal: React.FC = () => {
|
|||||||
<Timelines
|
<Timelines
|
||||||
name='Screen-Local-Root'
|
name='Screen-Local-Root'
|
||||||
content={[
|
content={[
|
||||||
{ title: t('headers.local.segments.left'), page: 'Following' },
|
{ title: t('local:heading.segments.left'), page: 'Following' },
|
||||||
{ title: t('headers.local.segments.right'), page: 'Local' }
|
{ title: t('local:heading.segments.right'), page: 'Local' }
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
@ -11,9 +11,11 @@ import { updateLocal } from 'src/utils/slices/instancesSlice'
|
|||||||
import { useNavigation } from '@react-navigation/native'
|
import { useNavigation } from '@react-navigation/native'
|
||||||
import { useTheme } from 'src/utils/styles/ThemeManager'
|
import { useTheme } from 'src/utils/styles/ThemeManager'
|
||||||
|
|
||||||
import constants from 'src/utils/styles/constants'
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import { StyleConstants } from 'src/utils/styles/constants'
|
||||||
|
|
||||||
const Login: React.FC = () => {
|
const Login: React.FC = () => {
|
||||||
|
const { t } = useTranslation('meRoot')
|
||||||
const { theme } = useTheme()
|
const { theme } = useTheme()
|
||||||
const navigation = useNavigation()
|
const navigation = useNavigation()
|
||||||
const dispatch = useDispatch()
|
const dispatch = useDispatch()
|
||||||
@ -126,7 +128,7 @@ const Login: React.FC = () => {
|
|||||||
color: theme.primary,
|
color: theme.primary,
|
||||||
borderColor: theme.border,
|
borderColor: theme.border,
|
||||||
borderWidth: 1,
|
borderWidth: 1,
|
||||||
padding: constants.SPACING_M
|
padding: StyleConstants.Spacing.M
|
||||||
}}
|
}}
|
||||||
onChangeText={onChangeText}
|
onChangeText={onChangeText}
|
||||||
autoCapitalize='none'
|
autoCapitalize='none'
|
||||||
@ -138,12 +140,12 @@ const Login: React.FC = () => {
|
|||||||
onSubmitEditing={async () =>
|
onSubmitEditing={async () =>
|
||||||
isSuccess && data && data.uri && (await createApplication())
|
isSuccess && data && data.uri && (await createApplication())
|
||||||
}
|
}
|
||||||
placeholder='输入服务器'
|
placeholder={t('content.login.server.placeholder')}
|
||||||
placeholderTextColor={theme.secondary}
|
placeholderTextColor={theme.secondary}
|
||||||
returnKeyType='go'
|
returnKeyType='go'
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
title='登录'
|
title={t('content.login.button')}
|
||||||
disabled={!data?.uri}
|
disabled={!data?.uri}
|
||||||
onPress={async () => await createApplication()}
|
onPress={async () => await createApplication()}
|
||||||
/>
|
/>
|
||||||
@ -158,7 +160,7 @@ const Login: React.FC = () => {
|
|||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
base: {
|
base: {
|
||||||
padding: constants.GLOBAL_PAGE_PADDING
|
padding: StyleConstants.Spacing.Global.PagePadding
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ const ScreenNotifications: React.FC = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack.Navigator
|
<Stack.Navigator
|
||||||
screenOptions={{ headerTitle: t('headers.notifications') }}
|
screenOptions={{ headerTitle: t('notifications:heading') }}
|
||||||
>
|
>
|
||||||
<Stack.Screen name='Screen-Notifications-Root'>
|
<Stack.Screen name='Screen-Notifications-Root'>
|
||||||
{() =>
|
{() =>
|
||||||
|
@ -10,8 +10,8 @@ const ScreenPublic: React.FC = () => {
|
|||||||
<Timelines
|
<Timelines
|
||||||
name='Screen-Public-Root'
|
name='Screen-Public-Root'
|
||||||
content={[
|
content={[
|
||||||
{ title: t('headers.public.segments.left'), page: 'LocalPublic' },
|
{ title: t('public:heading.segments.left'), page: 'LocalPublic' },
|
||||||
{ title: t('headers.public.segments.right'), page: 'RemotePublic' }
|
{ title: t('public:heading.segments.right'), page: 'RemotePublic' }
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
@ -5,14 +5,15 @@ import { Feather } from '@expo/vector-icons'
|
|||||||
|
|
||||||
import ParseContent from 'src/components/ParseContent'
|
import ParseContent from 'src/components/ParseContent'
|
||||||
import { useTheme } from 'src/utils/styles/ThemeManager'
|
import { useTheme } from 'src/utils/styles/ThemeManager'
|
||||||
|
import { StyleConstants } from 'src/utils/styles/constants'
|
||||||
import constants from 'src/utils/styles/constants'
|
import { useTranslation } from 'react-i18next'
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
account: Mastodon.Account | undefined
|
account: Mastodon.Account | undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
const AccountInformation: React.FC<Props> = ({ account }) => {
|
const AccountInformation: React.FC<Props> = ({ account }) => {
|
||||||
|
const { t } = useTranslation('sharedAccount')
|
||||||
const { theme } = useTheme()
|
const { theme } = useTheme()
|
||||||
const [avatarLoaded, setAvatarLoaded] = useState(false)
|
const [avatarLoaded, setAvatarLoaded] = useState(false)
|
||||||
|
|
||||||
@ -53,7 +54,7 @@ const AccountInformation: React.FC<Props> = ({ account }) => {
|
|||||||
>
|
>
|
||||||
<ParseContent
|
<ParseContent
|
||||||
content={field.name}
|
content={field.name}
|
||||||
size={constants.FONT_SIZE_M}
|
size={StyleConstants.Font.Size.M}
|
||||||
emojis={account.emojis}
|
emojis={account.emojis}
|
||||||
showFullLink
|
showFullLink
|
||||||
/>{' '}
|
/>{' '}
|
||||||
@ -62,7 +63,7 @@ const AccountInformation: React.FC<Props> = ({ account }) => {
|
|||||||
<Text style={{ width: '70%', color: theme.primary }}>
|
<Text style={{ width: '70%', color: theme.primary }}>
|
||||||
<ParseContent
|
<ParseContent
|
||||||
content={field.value}
|
content={field.value}
|
||||||
size={constants.FONT_SIZE_M}
|
size={StyleConstants.Font.Size.M}
|
||||||
emojis={account.emojis}
|
emojis={account.emojis}
|
||||||
showFullLink
|
showFullLink
|
||||||
/>
|
/>
|
||||||
@ -76,7 +77,7 @@ const AccountInformation: React.FC<Props> = ({ account }) => {
|
|||||||
<View style={styles.note}>
|
<View style={styles.note}>
|
||||||
<ParseContent
|
<ParseContent
|
||||||
content={account.note}
|
content={account.note}
|
||||||
size={constants.FONT_SIZE_M}
|
size={StyleConstants.Font.Size.M}
|
||||||
emojis={account.emojis}
|
emojis={account.emojis}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
@ -84,19 +85,20 @@ const AccountInformation: React.FC<Props> = ({ account }) => {
|
|||||||
|
|
||||||
{account?.created_at && (
|
{account?.created_at && (
|
||||||
<View style={styles.created_at}>
|
<View style={styles.created_at}>
|
||||||
<Feather name='calendar' size={constants.FONT_SIZE_M + 2} />
|
<Feather name='calendar' size={StyleConstants.Font.Size.M + 2} />
|
||||||
<Text
|
<Text
|
||||||
style={{
|
style={{
|
||||||
color: theme.primary,
|
color: theme.primary,
|
||||||
fontSize: constants.FONT_SIZE_M,
|
fontSize: StyleConstants.Font.Size.M,
|
||||||
marginLeft: constants.SPACING_XS
|
marginLeft: StyleConstants.Spacing.XS
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
加入时间:
|
{t('content.created_at', {
|
||||||
{new Date(account.created_at).toLocaleDateString('zh-CN', {
|
date: new Date(account.created_at).toLocaleDateString('zh-CN', {
|
||||||
year: 'numeric',
|
year: 'numeric',
|
||||||
month: 'long',
|
month: 'long',
|
||||||
day: 'numeric'
|
day: 'numeric'
|
||||||
|
})
|
||||||
})}
|
})}
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
@ -104,13 +106,19 @@ const AccountInformation: React.FC<Props> = ({ account }) => {
|
|||||||
|
|
||||||
<View style={styles.summary}>
|
<View style={styles.summary}>
|
||||||
<Text style={{ color: theme.primary }}>
|
<Text style={{ color: theme.primary }}>
|
||||||
{account?.statuses_count} 条嘟文
|
{t('content.summary.statuses_count', {
|
||||||
|
count: account?.statuses_count
|
||||||
|
})}
|
||||||
</Text>
|
</Text>
|
||||||
<Text style={{ color: theme.primary }}>
|
<Text style={{ color: theme.primary }}>
|
||||||
关注 {account?.followers_count} 人
|
{t('content.summary.followers_count', {
|
||||||
|
count: account?.followers_count
|
||||||
|
})}
|
||||||
</Text>
|
</Text>
|
||||||
<Text style={{ color: theme.primary }}>
|
<Text style={{ color: theme.primary }}>
|
||||||
被 {account?.following_count} 人关注
|
{t('content.summary.following_count', {
|
||||||
|
count: account?.following_count
|
||||||
|
})}
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
@ -119,33 +127,33 @@ const AccountInformation: React.FC<Props> = ({ account }) => {
|
|||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
information: {
|
information: {
|
||||||
marginTop: -30 - constants.GLOBAL_PAGE_PADDING,
|
marginTop: -30 - StyleConstants.Spacing.Global.PagePadding,
|
||||||
padding: constants.GLOBAL_PAGE_PADDING
|
padding: StyleConstants.Spacing.Global.PagePadding
|
||||||
},
|
},
|
||||||
avatar: {
|
avatar: {
|
||||||
width: constants.AVATAR_L,
|
width: StyleConstants.Avatar.L,
|
||||||
height: constants.AVATAR_L,
|
height: StyleConstants.Avatar.L,
|
||||||
borderRadius: 8
|
borderRadius: 8
|
||||||
},
|
},
|
||||||
display_name: {
|
display_name: {
|
||||||
fontSize: constants.FONT_SIZE_L,
|
fontSize: StyleConstants.Font.Size.L,
|
||||||
fontWeight: 'bold',
|
fontWeight: StyleConstants.Font.Weight.Bold,
|
||||||
marginTop: constants.SPACING_M,
|
marginTop: StyleConstants.Spacing.M,
|
||||||
marginBottom: constants.SPACING_XS
|
marginBottom: StyleConstants.Spacing.XS
|
||||||
},
|
},
|
||||||
account: {
|
account: {
|
||||||
fontSize: constants.FONT_SIZE_M,
|
fontSize: StyleConstants.Font.Size.M,
|
||||||
marginBottom: constants.SPACING_S
|
marginBottom: StyleConstants.Spacing.S
|
||||||
},
|
},
|
||||||
fields: {
|
fields: {
|
||||||
marginBottom: constants.SPACING_S
|
marginBottom: StyleConstants.Spacing.S
|
||||||
},
|
},
|
||||||
note: {
|
note: {
|
||||||
marginBottom: constants.SPACING_M
|
marginBottom: StyleConstants.Spacing.M
|
||||||
},
|
},
|
||||||
created_at: {
|
created_at: {
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
marginBottom: constants.SPACING_M
|
marginBottom: StyleConstants.Spacing.M
|
||||||
},
|
},
|
||||||
summary: {
|
summary: {
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
|
@ -3,12 +3,14 @@ import { Dimensions, FlatList, View } from 'react-native'
|
|||||||
import SegmentedControl from '@react-native-community/segmented-control'
|
import SegmentedControl from '@react-native-community/segmented-control'
|
||||||
|
|
||||||
import Timeline from 'src/components/Timelines/Timeline'
|
import Timeline from 'src/components/Timelines/Timeline'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
id: Mastodon.Account['id']
|
id: Mastodon.Account['id']
|
||||||
}
|
}
|
||||||
|
|
||||||
const AccountToots: React.FC<Props> = ({ id }) => {
|
const AccountToots: React.FC<Props> = ({ id }) => {
|
||||||
|
const { t } = useTranslation('sharedAccount')
|
||||||
const [segment, setSegment] = useState(0)
|
const [segment, setSegment] = useState(0)
|
||||||
const [segmentManuallyTriggered, setSegmentManuallyTriggered] = useState(
|
const [segmentManuallyTriggered, setSegmentManuallyTriggered] = useState(
|
||||||
false
|
false
|
||||||
@ -24,7 +26,11 @@ const AccountToots: React.FC<Props> = ({ id }) => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<SegmentedControl
|
<SegmentedControl
|
||||||
values={['嘟嘟', '嘟嘟和回复', '媒体']}
|
values={[
|
||||||
|
t('content.segments.left'),
|
||||||
|
t('content.segments.middle'),
|
||||||
|
t('content.segments.right')
|
||||||
|
]}
|
||||||
selectedIndex={segment}
|
selectedIndex={segment}
|
||||||
onChange={({ nativeEvent }) => {
|
onChange={({ nativeEvent }) => {
|
||||||
setSegmentManuallyTriggered(true)
|
setSegmentManuallyTriggered(true)
|
||||||
|
@ -1,7 +1,12 @@
|
|||||||
import React from 'react'
|
import { useNavigation } from '@react-navigation/native'
|
||||||
|
import React, { useRef, useState } from 'react'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import { createNativeStackNavigator } from 'react-native-screens/native-stack'
|
||||||
import { WebView } from 'react-native-webview'
|
import { WebView } from 'react-native-webview'
|
||||||
|
|
||||||
// Update page title
|
import { HeaderLeft, HeaderRight } from 'src/components/Header'
|
||||||
|
|
||||||
|
const Stack = createNativeStackNavigator()
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
route: {
|
route: {
|
||||||
@ -16,7 +21,42 @@ const ScreenSharedWebview: React.FC<Props> = ({
|
|||||||
params: { uri }
|
params: { uri }
|
||||||
}
|
}
|
||||||
}) => {
|
}) => {
|
||||||
return <WebView source={{ uri: uri }} />
|
const navigation = useNavigation()
|
||||||
|
const { t } = useTranslation('sharedWebview')
|
||||||
|
const [title, setTitle] = useState<string>(t('heading.loading'))
|
||||||
|
const webview = useRef<WebView>(null)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Stack.Navigator>
|
||||||
|
<Stack.Screen
|
||||||
|
name='Screen-Shared-Webview-Root'
|
||||||
|
options={{
|
||||||
|
title,
|
||||||
|
headerLeft: () => (
|
||||||
|
<HeaderLeft
|
||||||
|
icon='chevron-down'
|
||||||
|
onPress={() => navigation.goBack()}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
headerRight: () => (
|
||||||
|
<HeaderRight
|
||||||
|
icon='refresh-cw'
|
||||||
|
onPress={() => webview.current?.reload()}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{() => (
|
||||||
|
<WebView
|
||||||
|
ref={webview}
|
||||||
|
source={{ uri }}
|
||||||
|
onLoad={({ nativeEvent }) => setTitle(nativeEvent.title)}
|
||||||
|
onError={() => setTitle(t('heading.error'))}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Stack.Screen>
|
||||||
|
</Stack.Navigator>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ScreenSharedWebview
|
export default ScreenSharedWebview
|
||||||
|
@ -6,8 +6,11 @@ import ScreenSharedToot from 'src/screens/Shared/Toot'
|
|||||||
import ScreenSharedWebview from 'src/screens/Shared/Webview'
|
import ScreenSharedWebview from 'src/screens/Shared/Webview'
|
||||||
import Compose from 'src/screens/Shared/Compose'
|
import Compose from 'src/screens/Shared/Compose'
|
||||||
import ScreenSharedSearch from './Search'
|
import ScreenSharedSearch from './Search'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
|
||||||
const sharedScreens = (Stack: any) => {
|
const sharedScreens = (Stack: any) => {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
|
||||||
return [
|
return [
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
key='Screen-Shared-Account'
|
key='Screen-Shared-Account'
|
||||||
@ -32,16 +35,16 @@ const sharedScreens = (Stack: any) => {
|
|||||||
name='Screen-Shared-Toot'
|
name='Screen-Shared-Toot'
|
||||||
component={ScreenSharedToot}
|
component={ScreenSharedToot}
|
||||||
options={() => ({
|
options={() => ({
|
||||||
title: '对话'
|
title: t('sharedToot:heading')
|
||||||
})}
|
})}
|
||||||
/>,
|
/>,
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
key='Screen-Shared-Webview'
|
key='Screen-Shared-Webview'
|
||||||
name='Screen-Shared-Webview'
|
name='Screen-Shared-Webview'
|
||||||
component={ScreenSharedWebview}
|
component={ScreenSharedWebview}
|
||||||
// options={({ route }) => ({
|
options={() => ({
|
||||||
// title: `${route.params.domain}`
|
stackPresentation: 'modal'
|
||||||
// })}
|
})}
|
||||||
/>,
|
/>,
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
key='Screen-Shared-Compose'
|
key='Screen-Shared-Compose'
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
|
import { store } from 'src/store'
|
||||||
|
|
||||||
const relativeTime = (date: string) => {
|
const relativeTime = (date: string) => {
|
||||||
let units = {
|
const units = {
|
||||||
year: 24 * 60 * 60 * 1000 * 365,
|
year: 24 * 60 * 60 * 1000 * 365,
|
||||||
month: (24 * 60 * 60 * 1000 * 365) / 12,
|
month: (24 * 60 * 60 * 1000 * 365) / 12,
|
||||||
day: 24 * 60 * 60 * 1000,
|
day: 24 * 60 * 60 * 1000,
|
||||||
@ -8,14 +10,20 @@ const relativeTime = (date: string) => {
|
|||||||
second: 1000
|
second: 1000
|
||||||
}
|
}
|
||||||
|
|
||||||
let rtf = new Intl.RelativeTimeFormat('zh', { numeric: 'auto' })
|
const rtf = new Intl.RelativeTimeFormat(store.getState().settings.language, {
|
||||||
|
numeric: 'auto'
|
||||||
|
})
|
||||||
|
|
||||||
let elapsed: number = new Date(date) - new Date()
|
const elapsed = +new Date(date) - +new Date()
|
||||||
|
|
||||||
// "Math.abs" accounts for both "past" & "future" scenarios
|
// "Math.abs" accounts for both "past" & "future" scenarios
|
||||||
for (var u in units)
|
for (const u in units) {
|
||||||
if (Math.abs(elapsed) > units[u] || u == 'second')
|
// @ts-ignore
|
||||||
|
if (Math.abs(elapsed) > units[u] || u == 'second') {
|
||||||
|
// @ts-ignore
|
||||||
return rtf.format(Math.round(elapsed / units[u]), u)
|
return rtf.format(Math.round(elapsed / units[u]), u)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default relativeTime
|
export default relativeTime
|
||||||
|
@ -1,19 +1,30 @@
|
|||||||
export default {
|
const Base = 4
|
||||||
FONT_SIZE_S: 12,
|
|
||||||
FONT_SIZE_M: 14,
|
|
||||||
FONT_SIZE_L: 18,
|
|
||||||
|
|
||||||
FONT_WEIGHT_BOLD: '600',
|
export const StyleConstants = {
|
||||||
|
Font: {
|
||||||
|
Size: {
|
||||||
|
S: 12,
|
||||||
|
M: 14,
|
||||||
|
L: 18
|
||||||
|
},
|
||||||
|
Weight: {
|
||||||
|
Bold: '600' as '600'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
SPACING_XS: 4,
|
Spacing: {
|
||||||
SPACING_S: 8,
|
XS: Base,
|
||||||
SPACING_M: 16,
|
S: Base * 2,
|
||||||
SPACING_L: 24,
|
M: Base * 4,
|
||||||
SPACING_XL: 40,
|
L: Base * 6,
|
||||||
|
XL: Base * 10,
|
||||||
|
Global: {
|
||||||
|
PagePadding: Base * 6
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
GLOBAL_PAGE_PADDING: 24, // SPACING_M
|
Avatar: {
|
||||||
GLOBAL_SPACING_BASE: 8, // SPACING_S
|
S: 52,
|
||||||
|
L: 104
|
||||||
AVATAR_S: 52,
|
}
|
||||||
AVATAR_L: 104
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user