mirror of https://github.com/tooot-app/app
A lot of updates
This commit is contained in:
parent
0e3528d2cd
commit
9bfee02484
|
@ -60,7 +60,7 @@ export const Index: React.FC = () => {
|
||||||
name = 'bell'
|
name = 'bell'
|
||||||
break
|
break
|
||||||
case 'Screen-Me':
|
case 'Screen-Me':
|
||||||
name = focused ? 'smile' : 'meh'
|
name = focused ? 'meh' : 'smile'
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
name = 'alert-octagon'
|
name = 'alert-octagon'
|
||||||
|
|
|
@ -77,7 +77,7 @@ const BottomSheet: React.FC<Props> = ({ children, visible, handleDismiss }) => {
|
||||||
{
|
{
|
||||||
top,
|
top,
|
||||||
backgroundColor: theme.background,
|
backgroundColor: theme.background,
|
||||||
paddingBottom: insets.bottom
|
paddingBottom: insets.bottom || StyleConstants.Spacing.L
|
||||||
}
|
}
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
|
@ -108,15 +108,16 @@ const styles = StyleSheet.create({
|
||||||
},
|
},
|
||||||
handle: {
|
handle: {
|
||||||
alignSelf: 'center',
|
alignSelf: 'center',
|
||||||
width: StyleConstants.Spacing.Global.PagePadding * 8,
|
width: StyleConstants.Spacing.S * 8,
|
||||||
height: StyleConstants.Spacing.Global.PagePadding / 2,
|
height: StyleConstants.Spacing.S / 2,
|
||||||
borderRadius: 100,
|
borderRadius: 100,
|
||||||
top: -StyleConstants.Spacing.M * 2
|
top: -StyleConstants.Spacing.M * 2
|
||||||
},
|
},
|
||||||
cancel: {
|
cancel: {
|
||||||
padding: StyleConstants.Spacing.S,
|
padding: StyleConstants.Spacing.S,
|
||||||
borderWidth: 1,
|
borderWidth: 1,
|
||||||
borderRadius: 100
|
borderRadius: 100,
|
||||||
|
// marginBottom: StyleConstants.Spacing.L
|
||||||
},
|
},
|
||||||
text: {
|
text: {
|
||||||
fontSize: StyleConstants.Font.Size.L,
|
fontSize: StyleConstants.Font.Size.L,
|
||||||
|
|
|
@ -6,16 +6,16 @@ import { useTheme } from 'src/utils/styles/ThemeManager'
|
||||||
import { StyleConstants } from 'src/utils/styles/constants'
|
import { StyleConstants } from 'src/utils/styles/constants'
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
onPressFunction: () => void
|
onPress: () => void
|
||||||
icon: string
|
icon: string
|
||||||
text: string
|
text: string
|
||||||
}
|
}
|
||||||
|
|
||||||
const BottomSheetRow: React.FC<Props> = ({ onPressFunction, icon, text }) => {
|
const BottomSheetRow: React.FC<Props> = ({ onPress, icon, text }) => {
|
||||||
const { theme } = useTheme()
|
const { theme } = useTheme()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Pressable onPress={() => onPressFunction()} style={styles.pressable}>
|
<Pressable onPress={onPress} style={styles.pressable}>
|
||||||
<Feather
|
<Feather
|
||||||
name={icon}
|
name={icon}
|
||||||
color={theme.primary}
|
color={theme.primary}
|
||||||
|
@ -28,6 +28,7 @@ const BottomSheetRow: React.FC<Props> = ({ onPressFunction, icon, text }) => {
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
pressable: {
|
pressable: {
|
||||||
|
width: '100%',
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
marginBottom: StyleConstants.Spacing.L
|
marginBottom: StyleConstants.Spacing.L
|
||||||
},
|
},
|
||||||
|
|
|
@ -17,11 +17,11 @@ const HeaderLeft: React.FC<Props> = ({ onPress, text, icon }) => {
|
||||||
return (
|
return (
|
||||||
<Pressable onPress={onPress} style={styles.base}>
|
<Pressable onPress={onPress} style={styles.base}>
|
||||||
{text ? (
|
{text ? (
|
||||||
<Text style={[styles.text, { color: theme.link }]}>{text}</Text>
|
<Text style={[styles.text, { color: theme.primary }]}>{text}</Text>
|
||||||
) : (
|
) : (
|
||||||
<Feather
|
<Feather
|
||||||
name={icon || 'chevron-left'}
|
name={icon || 'chevron-left'}
|
||||||
color={theme.link}
|
color={theme.primary}
|
||||||
size={StyleConstants.Font.Size.L}
|
size={StyleConstants.Font.Size.L}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -28,11 +28,11 @@ const HeaderRight: React.FC<PropsText | PropsIcon> = ({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Pressable onPress={onPress} style={styles.base}>
|
<Pressable onPress={onPress} style={styles.base}>
|
||||||
{text && <Text style={[styles.text, { color: theme.link }]}>{text}</Text>}
|
{text && <Text style={[styles.text, { color: theme.primary }]}>{text}</Text>}
|
||||||
{icon && (
|
{icon && (
|
||||||
<Feather
|
<Feather
|
||||||
name={icon}
|
name={icon}
|
||||||
color={theme.link}
|
color={theme.primary}
|
||||||
size={StyleConstants.Font.Size.L}
|
size={StyleConstants.Font.Size.L}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
import React, { useCallback } from 'react'
|
import React, { useCallback } from 'react'
|
||||||
import { Text } from 'react-native'
|
import { StyleSheet, Text, View } from 'react-native'
|
||||||
import HTMLView, { HTMLViewNode } from 'react-native-htmlview'
|
import HTMLView from 'react-native-htmlview'
|
||||||
import { useNavigation } from '@react-navigation/native'
|
import { useNavigation } from '@react-navigation/native'
|
||||||
|
|
||||||
import Emojis from 'src/components/Timelines/Timeline/Shared/Emojis'
|
import Emojis from 'src/components/Timelines/Timeline/Shared/Emojis'
|
||||||
import { useTheme } from 'src/utils/styles/ThemeManager'
|
import { useTheme } from 'src/utils/styles/ThemeManager'
|
||||||
|
import { Feather } from '@expo/vector-icons'
|
||||||
|
import { StyleConstants } from 'src/utils/styles/constants'
|
||||||
|
|
||||||
// Prevent going to the same hashtag multiple times
|
// Prevent going to the same hashtag multiple times
|
||||||
const renderNode = ({
|
const renderNode = ({
|
||||||
|
@ -75,6 +77,11 @@ const renderNode = ({
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
<Feather
|
||||||
|
name='external-link'
|
||||||
|
size={StyleConstants.Font.Size.M}
|
||||||
|
color={theme.link}
|
||||||
|
/>{' '}
|
||||||
{showFullLink ? href : domain[1]}
|
{showFullLink ? href : domain[1]}
|
||||||
</Text>
|
</Text>
|
||||||
)
|
)
|
||||||
|
@ -88,7 +95,7 @@ export interface Props {
|
||||||
emojis?: Mastodon.Emoji[]
|
emojis?: Mastodon.Emoji[]
|
||||||
mentions?: Mastodon.Mention[]
|
mentions?: Mastodon.Mention[]
|
||||||
showFullLink?: boolean
|
showFullLink?: boolean
|
||||||
linesTruncated?: number
|
numberOfLines?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
const ParseContent: React.FC<Props> = ({
|
const ParseContent: React.FC<Props> = ({
|
||||||
|
@ -97,7 +104,7 @@ const ParseContent: React.FC<Props> = ({
|
||||||
emojis,
|
emojis,
|
||||||
mentions,
|
mentions,
|
||||||
showFullLink = false,
|
showFullLink = false,
|
||||||
linesTruncated = 10
|
numberOfLines = 10
|
||||||
}) => {
|
}) => {
|
||||||
const navigation = useNavigation()
|
const navigation = useNavigation()
|
||||||
const { theme } = useTheme()
|
const { theme } = useTheme()
|
||||||
|
@ -117,7 +124,11 @@ const ParseContent: React.FC<Props> = ({
|
||||||
[]
|
[]
|
||||||
)
|
)
|
||||||
const rootComponent = useCallback(({ children }) => {
|
const rootComponent = useCallback(({ children }) => {
|
||||||
return <Text numberOfLines={linesTruncated}>{children}</Text>
|
return (
|
||||||
|
<Text numberOfLines={numberOfLines} style={styles.root}>
|
||||||
|
{children}
|
||||||
|
</Text>
|
||||||
|
)
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -130,4 +141,10 @@ const ParseContent: React.FC<Props> = ({
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
root: {
|
||||||
|
lineHeight: StyleConstants.Font.LineHeight.M
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
export default ParseContent
|
export default ParseContent
|
||||||
|
|
|
@ -80,7 +80,7 @@ const Timeline: React.FC<Props> = ({
|
||||||
},
|
},
|
||||||
{ previous: true }
|
{ previous: true }
|
||||||
),
|
),
|
||||||
[disableRefresh]
|
[disableRefresh, flattenData]
|
||||||
)
|
)
|
||||||
const flOnEndReach = useCallback(
|
const flOnEndReach = useCallback(
|
||||||
() =>
|
() =>
|
||||||
|
@ -89,7 +89,7 @@ const Timeline: React.FC<Props> = ({
|
||||||
direction: 'next',
|
direction: 'next',
|
||||||
id: flattenData[flattenData.length - 1].id
|
id: flattenData[flattenData.length - 1].id
|
||||||
}),
|
}),
|
||||||
[disableRefresh]
|
[disableRefresh, flattenData]
|
||||||
)
|
)
|
||||||
|
|
||||||
let content
|
let content
|
||||||
|
@ -110,7 +110,7 @@ const Timeline: React.FC<Props> = ({
|
||||||
scrollEnabled={scrollEnabled} // For timeline in Account view
|
scrollEnabled={scrollEnabled} // For timeline in Account view
|
||||||
ItemSeparatorComponent={flItemSeparatorComponent}
|
ItemSeparatorComponent={flItemSeparatorComponent}
|
||||||
refreshing={!disableRefresh && isLoading}
|
refreshing={!disableRefresh && isLoading}
|
||||||
onEndReachedThreshold={!disableRefresh ? 0.5 : null}
|
onEndReachedThreshold={!disableRefresh ? 1 : null}
|
||||||
// require getItemLayout
|
// require getItemLayout
|
||||||
// {...(flattenPointer[0] && { initialScrollIndex: flattenPointer[0] })}
|
// {...(flattenPointer[0] && { initialScrollIndex: flattenPointer[0] })}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -106,7 +106,8 @@ const styles = StyleSheet.create({
|
||||||
statusView: {
|
statusView: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
padding: StyleConstants.Spacing.Global.PagePadding
|
padding: StyleConstants.Spacing.Global.PagePadding,
|
||||||
|
paddingBottom: StyleConstants.Spacing.M
|
||||||
},
|
},
|
||||||
status: {
|
status: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
|
|
|
@ -1,13 +1,5 @@
|
||||||
import React, { useCallback, useMemo, useState } from 'react'
|
import React, { useCallback, useMemo, useState } from 'react'
|
||||||
import {
|
import { ActionSheetIOS, Pressable, StyleSheet, Text, View } from 'react-native'
|
||||||
ActionSheetIOS,
|
|
||||||
Clipboard,
|
|
||||||
Modal,
|
|
||||||
Pressable,
|
|
||||||
StyleSheet,
|
|
||||||
Text,
|
|
||||||
View
|
|
||||||
} from 'react-native'
|
|
||||||
import { useMutation, useQueryCache } from 'react-query'
|
import { useMutation, useQueryCache } from 'react-query'
|
||||||
import { Feather } from '@expo/vector-icons'
|
import { Feather } from '@expo/vector-icons'
|
||||||
|
|
||||||
|
@ -17,6 +9,8 @@ import { useTheme } from 'src/utils/styles/ThemeManager'
|
||||||
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'
|
import { StyleConstants } from 'src/utils/styles/constants'
|
||||||
|
import BottomSheet from 'src/components/BottomSheet'
|
||||||
|
import BottomSheetRow from 'src/components/BottomSheet/Row'
|
||||||
|
|
||||||
const fireMutation = async ({
|
const fireMutation = async ({
|
||||||
id,
|
id,
|
||||||
|
@ -275,96 +269,85 @@ const ActionsStatus: React.FC<Props> = ({ queryKey, status }) => {
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
<Modal
|
<BottomSheet
|
||||||
animationType='fade'
|
|
||||||
presentationStyle='overFullScreen'
|
|
||||||
transparent
|
|
||||||
visible={bottomSheetVisible}
|
visible={bottomSheetVisible}
|
||||||
|
handleDismiss={() => setBottomSheetVisible(false)}
|
||||||
>
|
>
|
||||||
<Pressable
|
<BottomSheetRow
|
||||||
style={styles.modalBackground}
|
onPress={() => {
|
||||||
onPress={() => setBottomSheetVisible(false)}
|
ActionSheetIOS.showShareActionSheetWithOptions(
|
||||||
>
|
{
|
||||||
<View style={styles.modalSheet}>
|
url: status.uri,
|
||||||
<Pressable
|
excludedActivityTypes: [
|
||||||
onPress={() =>
|
'com.apple.UIKit.activity.Mail',
|
||||||
ActionSheetIOS.showShareActionSheetWithOptions(
|
'com.apple.UIKit.activity.Print',
|
||||||
{
|
'com.apple.UIKit.activity.SaveToCameraRoll',
|
||||||
url: status.uri,
|
'com.apple.UIKit.activity.OpenInIBooks'
|
||||||
excludedActivityTypes: [
|
]
|
||||||
'com.apple.UIKit.activity.Mail',
|
},
|
||||||
'com.apple.UIKit.activity.Print',
|
() => {},
|
||||||
'com.apple.UIKit.activity.SaveToCameraRoll',
|
() => {
|
||||||
'com.apple.UIKit.activity.OpenInIBooks'
|
setBottomSheetVisible(false)
|
||||||
]
|
toast({ type: 'success', content: '分享成功' })
|
||||||
},
|
|
||||||
() => {},
|
|
||||||
() => {
|
|
||||||
setBottomSheetVisible(false)
|
|
||||||
toast({ type: 'success', content: '分享成功' })
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
>
|
)
|
||||||
<Text>分享</Text>
|
}}
|
||||||
</Pressable>
|
icon='share'
|
||||||
<Pressable
|
text={'分享嘟嘟'}
|
||||||
onPress={() => {
|
/>
|
||||||
Clipboard.setString(status.uri)
|
{status.account.id === localAccountId && (
|
||||||
setBottomSheetVisible(false)
|
<BottomSheetRow
|
||||||
toast({ type: 'success', content: '链接复制成功' })
|
onPress={() => {
|
||||||
}}
|
setBottomSheetVisible(false)
|
||||||
>
|
mutateAction({
|
||||||
<Text>复制链接</Text>
|
id: status.id,
|
||||||
</Pressable>
|
type: 'delete',
|
||||||
{status.account.id === localAccountId && (
|
stateKey: 'id'
|
||||||
<Pressable
|
})
|
||||||
onPress={() => {
|
}}
|
||||||
setBottomSheetVisible(false)
|
icon='trash'
|
||||||
mutateAction({
|
text='删除嘟嘟'
|
||||||
id: status.id,
|
/>
|
||||||
type: 'delete',
|
)}
|
||||||
stateKey: 'id'
|
{status.account.id === localAccountId && (
|
||||||
})
|
<BottomSheetRow
|
||||||
}}
|
onPress={() => {
|
||||||
>
|
console.warn('功能未开发')
|
||||||
<Text>删除</Text>
|
}}
|
||||||
</Pressable>
|
icon='trash'
|
||||||
)}
|
text='删除并重发'
|
||||||
<Text>(删除并重发)</Text>
|
/>
|
||||||
<Pressable
|
)}
|
||||||
onPress={() => {
|
<BottomSheetRow
|
||||||
setBottomSheetVisible(false)
|
onPress={() => {
|
||||||
mutateAction({
|
setBottomSheetVisible(false)
|
||||||
id: status.id,
|
mutateAction({
|
||||||
type: 'mute',
|
id: status.id,
|
||||||
stateKey: 'muted',
|
type: 'mute',
|
||||||
prevState: status.muted
|
stateKey: 'muted',
|
||||||
})
|
prevState: status.muted
|
||||||
}}
|
})
|
||||||
>
|
}}
|
||||||
<Text>{status.muted ? '取消静音' : '静音'}</Text>
|
icon='volume-x'
|
||||||
</Pressable>
|
text={status.muted ? '取消静音' : '静音'}
|
||||||
{/* Also note that reblogs cannot be pinned. */}
|
/>
|
||||||
{status.account.id === localAccountId && (
|
{/* Also note that reblogs cannot be pinned. */}
|
||||||
<Pressable
|
{status.account.id === localAccountId && (
|
||||||
onPress={() => {
|
<BottomSheetRow
|
||||||
setBottomSheetVisible(false)
|
onPress={() => {
|
||||||
mutateAction({
|
setBottomSheetVisible(false)
|
||||||
id: status.id,
|
mutateAction({
|
||||||
type: 'pin',
|
id: status.id,
|
||||||
stateKey: 'pinned',
|
type: 'pin',
|
||||||
prevState: status.pinned
|
stateKey: 'pinned',
|
||||||
})
|
prevState: status.pinned
|
||||||
}}
|
})
|
||||||
>
|
}}
|
||||||
<Text>{status.pinned ? '取消置顶' : '置顶'}</Text>
|
icon='anchor'
|
||||||
</Pressable>
|
text={status.pinned ? '取消置顶' : '置顶'}
|
||||||
)}
|
/>
|
||||||
<Text>静音用户,屏蔽用户,屏蔽域名,举报用户</Text>
|
)}
|
||||||
</View>
|
</BottomSheet>
|
||||||
</Pressable>
|
|
||||||
</Modal>
|
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,15 @@
|
||||||
import React, { useCallback } from 'react'
|
import React, { useCallback } from 'react'
|
||||||
import { Image, Pressable, StyleSheet, Text, View } from 'react-native'
|
import { Image, Pressable, StyleSheet, Text, View } from 'react-native'
|
||||||
import { useNavigation } from '@react-navigation/native'
|
import { useNavigation } from '@react-navigation/native'
|
||||||
|
import { StyleConstants } from 'src/utils/styles/constants'
|
||||||
|
import { useTheme } from 'src/utils/styles/ThemeManager'
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
card: Mastodon.Card
|
card: Mastodon.Card
|
||||||
}
|
}
|
||||||
|
|
||||||
const Card: React.FC<Props> = ({ card }) => {
|
const Card: React.FC<Props> = ({ card }) => {
|
||||||
|
const { theme } = useTheme()
|
||||||
const navigation = useNavigation()
|
const navigation = useNavigation()
|
||||||
const onPress = useCallback(() => {
|
const onPress = useCallback(() => {
|
||||||
navigation.navigate('Screen-Shared-Webview', {
|
navigation.navigate('Screen-Shared-Webview', {
|
||||||
|
@ -15,20 +18,35 @@ const Card: React.FC<Props> = ({ card }) => {
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Pressable style={styles.card} onPress={onPress}>
|
<Pressable
|
||||||
|
style={[styles.card, { borderColor: theme.border }]}
|
||||||
|
onPress={onPress}
|
||||||
|
>
|
||||||
{card.image && (
|
{card.image && (
|
||||||
<View style={styles.left}>
|
<View style={styles.left}>
|
||||||
<Image source={{ uri: card.image }} style={styles.image} />
|
<Image source={{ uri: card.image }} style={styles.image} />
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
<View style={styles.right}>
|
<View style={styles.right}>
|
||||||
<Text numberOfLines={1}>{card.title}</Text>
|
<Text
|
||||||
|
numberOfLines={2}
|
||||||
|
style={[styles.rightTitle, { color: theme.primary }]}
|
||||||
|
>
|
||||||
|
{card.title}
|
||||||
|
</Text>
|
||||||
{card.description ? (
|
{card.description ? (
|
||||||
<Text numberOfLines={2}>{card.description}</Text>
|
<Text
|
||||||
|
numberOfLines={1}
|
||||||
|
style={[styles.rightDescription, { color: theme.primary }]}
|
||||||
|
>
|
||||||
|
{card.description}
|
||||||
|
</Text>
|
||||||
) : (
|
) : (
|
||||||
<></>
|
<></>
|
||||||
)}
|
)}
|
||||||
<Text numberOfLines={1}>{card.url}</Text>
|
<Text numberOfLines={1} style={{ color: theme.secondary }}>
|
||||||
|
{card.url}
|
||||||
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
</Pressable>
|
</Pressable>
|
||||||
)
|
)
|
||||||
|
@ -38,18 +56,30 @@ const styles = StyleSheet.create({
|
||||||
card: {
|
card: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
height: 70,
|
height: StyleConstants.Avatar.L,
|
||||||
marginTop: 12
|
marginTop: StyleConstants.Spacing.M,
|
||||||
|
borderWidth: 0.5,
|
||||||
|
borderRadius: 6
|
||||||
},
|
},
|
||||||
left: {
|
left: {
|
||||||
width: 70
|
width: StyleConstants.Avatar.L
|
||||||
},
|
},
|
||||||
image: {
|
image: {
|
||||||
width: '100%',
|
width: '100%',
|
||||||
height: '100%'
|
height: '100%',
|
||||||
|
borderTopLeftRadius: 6,
|
||||||
|
borderBottomLeftRadius: 6
|
||||||
},
|
},
|
||||||
right: {
|
right: {
|
||||||
flex: 1
|
flex: 1,
|
||||||
|
padding: StyleConstants.Spacing.S
|
||||||
|
},
|
||||||
|
rightTitle: {
|
||||||
|
marginBottom: StyleConstants.Spacing.XS,
|
||||||
|
fontWeight: StyleConstants.Font.Weight.Bold
|
||||||
|
},
|
||||||
|
rightDescription: {
|
||||||
|
marginBottom: StyleConstants.Spacing.XS
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { Image, StyleSheet, Text } from 'react-native'
|
import { Image, StyleSheet, Text, 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 { StyleConstants } from 'src/utils/styles/constants'
|
||||||
|
|
||||||
|
@ -22,19 +22,20 @@ const Emojis: React.FC<Props> = ({
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
text: {
|
text: {
|
||||||
fontSize: size,
|
fontSize: size,
|
||||||
lineHeight: size + 2,
|
|
||||||
color: theme.primary,
|
color: theme.primary,
|
||||||
...(fontBold && { fontWeight: StyleConstants.Font.Weight.Bold })
|
...(fontBold && { fontWeight: StyleConstants.Font.Weight.Bold })
|
||||||
},
|
},
|
||||||
image: {
|
image: {
|
||||||
width: size,
|
width: size,
|
||||||
height: size
|
height: size,
|
||||||
|
paddingTop: 1,
|
||||||
|
marginBottom: -1
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
const hasEmojis = content.match(regexEmoji)
|
const hasEmojis = content.match(regexEmoji)
|
||||||
|
|
||||||
return hasEmojis ? (
|
return (
|
||||||
<>
|
<Text>
|
||||||
{content.split(regexEmoji).map((str, i) => {
|
{content.split(regexEmoji).map((str, i) => {
|
||||||
if (str.match(regexEmoji)) {
|
if (str.match(regexEmoji)) {
|
||||||
const emojiShortcode = str.split(regexEmoji)[1]
|
const emojiShortcode = str.split(regexEmoji)[1]
|
||||||
|
@ -46,23 +47,26 @@ const Emojis: React.FC<Props> = ({
|
||||||
{emojiShortcode}
|
{emojiShortcode}
|
||||||
</Text>
|
</Text>
|
||||||
) : (
|
) : (
|
||||||
<Image
|
<View key={i} style={styles.image}>
|
||||||
key={i}
|
<Image
|
||||||
source={{ uri: emojis[emojiIndex].url }}
|
key={i}
|
||||||
style={styles.image}
|
resizeMode='contain'
|
||||||
/>
|
source={{ uri: emojis[emojiIndex].url }}
|
||||||
|
style={{ width: '100%', height: '100%' }}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
return (
|
return str ? (
|
||||||
<Text key={i} style={styles.text}>
|
<Text key={i} style={styles.text}>
|
||||||
{str}
|
{str}
|
||||||
</Text>
|
</Text>
|
||||||
|
) : (
|
||||||
|
undefined
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
})}
|
})}
|
||||||
</>
|
</Text>
|
||||||
) : (
|
|
||||||
<Text style={styles.text}>{content}</Text>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -166,7 +166,7 @@ const HeaderDefault: React.FC<Props> = ({
|
||||||
<View>
|
<View>
|
||||||
<View style={styles.nameAndAction}>
|
<View style={styles.nameAndAction}>
|
||||||
<View style={styles.name}>
|
<View style={styles.name}>
|
||||||
{emojis ? (
|
{emojis?.length ? (
|
||||||
<Emojis
|
<Emojis
|
||||||
content={name}
|
content={name}
|
||||||
emojis={emojis}
|
emojis={emojis}
|
||||||
|
@ -174,7 +174,10 @@ const HeaderDefault: React.FC<Props> = ({
|
||||||
fontBold={true}
|
fontBold={true}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<Text numberOfLines={1} style={{ color: theme.primary }}>
|
<Text
|
||||||
|
numberOfLines={1}
|
||||||
|
style={[styles.nameWithoutEmoji, { color: theme.primary }]}
|
||||||
|
>
|
||||||
{name}
|
{name}
|
||||||
</Text>
|
</Text>
|
||||||
)}
|
)}
|
||||||
|
@ -193,6 +196,7 @@ const HeaderDefault: React.FC<Props> = ({
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
<View style={styles.meta}>
|
<View style={styles.meta}>
|
||||||
<View>
|
<View>
|
||||||
<Text style={[styles.created_at, { color: theme.secondary }]}>
|
<Text style={[styles.created_at, { color: theme.secondary }]}>
|
||||||
|
@ -224,7 +228,7 @@ const HeaderDefault: React.FC<Props> = ({
|
||||||
>
|
>
|
||||||
{accountId !== localAccountId && (
|
{accountId !== localAccountId && (
|
||||||
<BottomSheetRow
|
<BottomSheetRow
|
||||||
onPressFunction={() => {
|
onPress={() => {
|
||||||
setModalVisible(false)
|
setModalVisible(false)
|
||||||
mutateAction({
|
mutateAction({
|
||||||
id: accountId,
|
id: accountId,
|
||||||
|
@ -238,7 +242,7 @@ const HeaderDefault: React.FC<Props> = ({
|
||||||
)}
|
)}
|
||||||
{accountId !== localAccountId && (
|
{accountId !== localAccountId && (
|
||||||
<BottomSheetRow
|
<BottomSheetRow
|
||||||
onPressFunction={() => {
|
onPress={() => {
|
||||||
setModalVisible(false)
|
setModalVisible(false)
|
||||||
mutateAction({
|
mutateAction({
|
||||||
id: accountId,
|
id: accountId,
|
||||||
|
@ -252,7 +256,7 @@ const HeaderDefault: React.FC<Props> = ({
|
||||||
)}
|
)}
|
||||||
{domain !== localDomain && (
|
{domain !== localDomain && (
|
||||||
<BottomSheetRow
|
<BottomSheetRow
|
||||||
onPressFunction={() => {
|
onPress={() => {
|
||||||
setModalVisible(false)
|
setModalVisible(false)
|
||||||
mutateAction({
|
mutateAction({
|
||||||
id: domain,
|
id: domain,
|
||||||
|
@ -265,7 +269,7 @@ const HeaderDefault: React.FC<Props> = ({
|
||||||
)}
|
)}
|
||||||
{accountId !== localAccountId && (
|
{accountId !== localAccountId && (
|
||||||
<BottomSheetRow
|
<BottomSheetRow
|
||||||
onPressFunction={() => {
|
onPress={() => {
|
||||||
setModalVisible(false)
|
setModalVisible(false)
|
||||||
mutateAction({
|
mutateAction({
|
||||||
id: accountId,
|
id: accountId,
|
||||||
|
@ -288,17 +292,20 @@ const styles = StyleSheet.create({
|
||||||
justifyContent: 'space-between'
|
justifyContent: 'space-between'
|
||||||
},
|
},
|
||||||
name: {
|
name: {
|
||||||
flexBasis: '80%',
|
flexBasis: '90%',
|
||||||
flexDirection: 'row'
|
flexDirection: 'row'
|
||||||
},
|
},
|
||||||
|
nameWithoutEmoji: {
|
||||||
|
fontSize: StyleConstants.Font.Size.M,
|
||||||
|
fontWeight: StyleConstants.Font.Weight.Bold
|
||||||
|
},
|
||||||
action: {
|
action: {
|
||||||
flexBasis: '20%',
|
alignItems: 'flex-end'
|
||||||
alignItems: 'center'
|
|
||||||
},
|
},
|
||||||
account: {
|
account: {
|
||||||
flexShrink: 1,
|
flexShrink: 1,
|
||||||
marginLeft: StyleConstants.Spacing.XS,
|
marginLeft: StyleConstants.Spacing.XS
|
||||||
lineHeight: StyleConstants.Font.Size.M + 2
|
// lineHeight: StyleConstants.Font.LineHeight.M
|
||||||
},
|
},
|
||||||
meta: {
|
meta: {
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
|
|
|
@ -17,6 +17,10 @@ export default {
|
||||||
dark: '深色模式',
|
dark: '深色模式',
|
||||||
cancel: '$t(common:buttons.cancel)'
|
cancel: '$t(common:buttons.cancel)'
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
copyrights: {
|
||||||
|
heading: '版权信息'
|
||||||
|
},
|
||||||
|
version: '版本 v{{version}}'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { ActionSheetIOS } from 'react-native'
|
import { ActionSheetIOS, StyleSheet, Text } from 'react-native'
|
||||||
import { useDispatch, useSelector } from 'react-redux'
|
import { useDispatch, useSelector } from 'react-redux'
|
||||||
|
|
||||||
import { MenuContainer, MenuItem } from 'src/components/Menu'
|
import { MenuContainer, MenuItem } from 'src/components/Menu'
|
||||||
|
@ -10,81 +10,101 @@ import {
|
||||||
getSettingsLanguage,
|
getSettingsLanguage,
|
||||||
getSettingsTheme
|
getSettingsTheme
|
||||||
} from 'src/utils/slices/settingsSlice'
|
} from 'src/utils/slices/settingsSlice'
|
||||||
|
import { StyleConstants } from 'src/utils/styles/constants'
|
||||||
import { useTheme } from 'src/utils/styles/ThemeManager'
|
import { useTheme } from 'src/utils/styles/ThemeManager'
|
||||||
|
|
||||||
const ScreenMeSettings: React.FC = () => {
|
const ScreenMeSettings: React.FC = () => {
|
||||||
const { t, i18n } = useTranslation('meSettings')
|
const { t, i18n } = useTranslation('meSettings')
|
||||||
const { setTheme } = useTheme()
|
const { setTheme, theme } = useTheme()
|
||||||
const settingsLanguage = useSelector(getSettingsLanguage)
|
const settingsLanguage = useSelector(getSettingsLanguage)
|
||||||
const settingsTheme = useSelector(getSettingsTheme)
|
const settingsTheme = useSelector(getSettingsTheme)
|
||||||
const dispatch = useDispatch()
|
const dispatch = useDispatch()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MenuContainer marginTop={true}>
|
<>
|
||||||
<MenuItem
|
<MenuContainer marginTop={true}>
|
||||||
title={t('content.language.heading')}
|
<MenuItem
|
||||||
content={t(`content.language.options.${settingsLanguage}`)}
|
title={t('content.language.heading')}
|
||||||
iconBack='chevron-right'
|
content={t(`content.language.options.${settingsLanguage}`)}
|
||||||
onPress={() =>
|
iconBack='chevron-right'
|
||||||
ActionSheetIOS.showActionSheetWithOptions(
|
onPress={() =>
|
||||||
{
|
ActionSheetIOS.showActionSheetWithOptions(
|
||||||
options: [
|
{
|
||||||
t('content.language.options.zh'),
|
options: [
|
||||||
t('content.language.options.en'),
|
t('content.language.options.zh'),
|
||||||
t('content.language.options.cancel')
|
t('content.language.options.en'),
|
||||||
],
|
t('content.language.options.cancel')
|
||||||
cancelButtonIndex: 2
|
],
|
||||||
},
|
cancelButtonIndex: 2
|
||||||
buttonIndex => {
|
},
|
||||||
switch (buttonIndex) {
|
buttonIndex => {
|
||||||
case 0:
|
switch (buttonIndex) {
|
||||||
dispatch(changeLanguage('zh'))
|
case 0:
|
||||||
i18n.changeLanguage('zh')
|
dispatch(changeLanguage('zh'))
|
||||||
break
|
i18n.changeLanguage('zh')
|
||||||
case 1:
|
break
|
||||||
dispatch(changeLanguage('en'))
|
case 1:
|
||||||
i18n.changeLanguage('en')
|
dispatch(changeLanguage('en'))
|
||||||
break
|
i18n.changeLanguage('en')
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
)
|
||||||
)
|
}
|
||||||
}
|
/>
|
||||||
/>
|
<MenuItem
|
||||||
<MenuItem
|
title={t('content.theme.heading')}
|
||||||
title={t('content.theme.heading')}
|
content={t(`content.theme.options.${settingsTheme}`)}
|
||||||
content={t(`content.theme.options.${settingsTheme}`)}
|
iconBack='chevron-right'
|
||||||
iconBack='chevron-right'
|
onPress={() =>
|
||||||
onPress={() =>
|
ActionSheetIOS.showActionSheetWithOptions(
|
||||||
ActionSheetIOS.showActionSheetWithOptions(
|
{
|
||||||
{
|
options: [
|
||||||
options: [
|
t('content.theme.options.auto'),
|
||||||
t('content.theme.options.auto'),
|
t('content.theme.options.light'),
|
||||||
t('content.theme.options.light'),
|
t('content.theme.options.dark'),
|
||||||
t('content.theme.options.dark'),
|
t('content.theme.options.cancel')
|
||||||
t('content.theme.options.cancel')
|
],
|
||||||
],
|
cancelButtonIndex: 3
|
||||||
cancelButtonIndex: 3
|
},
|
||||||
},
|
buttonIndex => {
|
||||||
buttonIndex => {
|
switch (buttonIndex) {
|
||||||
switch (buttonIndex) {
|
case 0:
|
||||||
case 0:
|
dispatch(changeTheme('auto'))
|
||||||
dispatch(changeTheme('auto'))
|
break
|
||||||
break
|
case 1:
|
||||||
case 1:
|
dispatch(changeTheme('light'))
|
||||||
dispatch(changeTheme('light'))
|
setTheme('light')
|
||||||
setTheme('light')
|
break
|
||||||
break
|
case 2:
|
||||||
case 2:
|
dispatch(changeTheme('dark'))
|
||||||
dispatch(changeTheme('dark'))
|
setTheme('dark')
|
||||||
setTheme('dark')
|
break
|
||||||
break
|
}
|
||||||
}
|
}
|
||||||
}
|
)
|
||||||
)
|
}
|
||||||
}
|
/>
|
||||||
/>
|
</MenuContainer>
|
||||||
</MenuContainer>
|
<MenuContainer>
|
||||||
|
<MenuItem
|
||||||
|
title={t('content.copyrights.heading')}
|
||||||
|
iconBack='chevron-right'
|
||||||
|
></MenuItem>
|
||||||
|
<Text style={[styles.version, { color: theme.secondary }]}>
|
||||||
|
{t('content.version', { version: '1.0.0' })}
|
||||||
|
</Text>
|
||||||
|
</MenuContainer>
|
||||||
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
version: {
|
||||||
|
textAlign: 'center',
|
||||||
|
fontSize: StyleConstants.Font.Size.S,
|
||||||
|
marginTop: StyleConstants.Spacing.M
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
export default ScreenMeSettings
|
export default ScreenMeSettings
|
||||||
|
|
|
@ -7,6 +7,7 @@ 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 { StyleConstants } from 'src/utils/styles/constants'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import Emojis from 'src/components/Timelines/Timeline/Shared/Emojis'
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
account: Mastodon.Account | undefined
|
account: Mastodon.Account | undefined
|
||||||
|
@ -17,7 +18,6 @@ const AccountInformation: React.FC<Props> = ({ account }) => {
|
||||||
const { theme } = useTheme()
|
const { theme } = useTheme()
|
||||||
const [avatarLoaded, setAvatarLoaded] = useState(false)
|
const [avatarLoaded, setAvatarLoaded] = useState(false)
|
||||||
|
|
||||||
// add emoji support
|
|
||||||
return (
|
return (
|
||||||
<View style={styles.information}>
|
<View style={styles.information}>
|
||||||
{/* <Text>Moved or not: {account.moved}</Text> */}
|
{/* <Text>Moved or not: {account.moved}</Text> */}
|
||||||
|
@ -29,27 +29,69 @@ const AccountInformation: React.FC<Props> = ({ account }) => {
|
||||||
/>
|
/>
|
||||||
</ShimmerPlaceholder>
|
</ShimmerPlaceholder>
|
||||||
|
|
||||||
<Text style={[styles.display_name, { color: theme.primary }]}>
|
<View style={styles.display_name}>
|
||||||
{account?.display_name || account?.username}
|
{account?.emojis ? (
|
||||||
{account?.bot && (
|
<Emojis
|
||||||
<Feather name='hard-drive' style={styles.display_name} />
|
content={account?.display_name || account?.username}
|
||||||
|
emojis={account.emojis}
|
||||||
|
size={StyleConstants.Font.Size.L}
|
||||||
|
fontBold={true}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<Text
|
||||||
|
style={{
|
||||||
|
color: theme.primary,
|
||||||
|
fontSize: StyleConstants.Font.Size.L,
|
||||||
|
fontWeight: StyleConstants.Font.Weight.Bold
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{account?.display_name || account?.username}
|
||||||
|
</Text>
|
||||||
)}
|
)}
|
||||||
</Text>
|
</View>
|
||||||
|
|
||||||
<Text style={[styles.account, { color: theme.secondary }]}>
|
<View style={styles.account}>
|
||||||
@{account?.acct}
|
<Text
|
||||||
{account?.locked && <Feather name='lock' />}
|
style={{
|
||||||
</Text>
|
color: theme.secondary,
|
||||||
|
fontSize: StyleConstants.Font.Size.M
|
||||||
|
}}
|
||||||
|
selectable
|
||||||
|
>
|
||||||
|
@{account?.acct}
|
||||||
|
</Text>
|
||||||
|
{account?.locked && (
|
||||||
|
<Feather
|
||||||
|
name='lock'
|
||||||
|
style={styles.account_types}
|
||||||
|
color={theme.secondary}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{account?.bot && (
|
||||||
|
<Feather
|
||||||
|
name='hard-drive'
|
||||||
|
style={styles.account_types}
|
||||||
|
color={theme.secondary}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
|
||||||
{account?.fields && (
|
{account?.fields && account.fields.length > 0 && (
|
||||||
<View style={styles.fields}>
|
<View style={[styles.fields, { borderTopColor: theme.border }]}>
|
||||||
{account.fields.map((field, index) => (
|
{account.fields.map((field, index) => (
|
||||||
<View key={index} style={{ flex: 1, flexDirection: 'row' }}>
|
<View
|
||||||
<Text
|
key={index}
|
||||||
|
style={[styles.field, { borderBottomColor: theme.border }]}
|
||||||
|
>
|
||||||
|
<View
|
||||||
style={{
|
style={{
|
||||||
width: '30%',
|
flexBasis: '30%',
|
||||||
alignSelf: 'center',
|
alignItems: 'center',
|
||||||
color: theme.primary
|
justifyContent: 'center',
|
||||||
|
borderRightWidth: 1,
|
||||||
|
borderRightColor: theme.border,
|
||||||
|
paddingLeft: StyleConstants.Spacing.S,
|
||||||
|
paddingRight: StyleConstants.Spacing.S
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<ParseContent
|
<ParseContent
|
||||||
|
@ -57,17 +99,31 @@ const AccountInformation: React.FC<Props> = ({ account }) => {
|
||||||
size={StyleConstants.Font.Size.M}
|
size={StyleConstants.Font.Size.M}
|
||||||
emojis={account.emojis}
|
emojis={account.emojis}
|
||||||
showFullLink
|
showFullLink
|
||||||
/>{' '}
|
/>
|
||||||
{field.verified_at && <Feather name='check-circle' />}
|
{field.verified_at && (
|
||||||
</Text>
|
<Feather
|
||||||
<Text style={{ width: '70%', color: theme.primary }}>
|
name='check-circle'
|
||||||
|
size={StyleConstants.Font.Size.M}
|
||||||
|
color={theme.primary}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
<View
|
||||||
|
style={{
|
||||||
|
flexBasis: '70%',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
paddingLeft: StyleConstants.Spacing.S,
|
||||||
|
paddingRight: StyleConstants.Spacing.S
|
||||||
|
}}
|
||||||
|
>
|
||||||
<ParseContent
|
<ParseContent
|
||||||
content={field.value}
|
content={field.value}
|
||||||
size={StyleConstants.Font.Size.M}
|
size={StyleConstants.Font.Size.M}
|
||||||
emojis={account.emojis}
|
emojis={account.emojis}
|
||||||
showFullLink
|
showFullLink
|
||||||
/>
|
/>
|
||||||
</Text>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
))}
|
))}
|
||||||
</View>
|
</View>
|
||||||
|
@ -83,41 +139,46 @@ const AccountInformation: React.FC<Props> = ({ account }) => {
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{account?.created_at && (
|
<View style={styles.created_at}>
|
||||||
<View style={styles.created_at}>
|
<Feather
|
||||||
<Feather name='calendar' size={StyleConstants.Font.Size.M + 2} />
|
name='calendar'
|
||||||
<Text
|
size={StyleConstants.Font.Size.M + 2}
|
||||||
style={{
|
color={theme.secondary}
|
||||||
color: theme.primary,
|
style={styles.created_at_icon}
|
||||||
fontSize: StyleConstants.Font.Size.M,
|
/>
|
||||||
marginLeft: StyleConstants.Spacing.XS
|
<Text
|
||||||
}}
|
style={{
|
||||||
>
|
color: theme.secondary,
|
||||||
{t('content.created_at', {
|
fontSize: StyleConstants.Font.Size.M
|
||||||
date: new Date(account.created_at).toLocaleDateString('zh-CN', {
|
}}
|
||||||
|
>
|
||||||
|
{t(
|
||||||
|
'content.created_at',
|
||||||
|
{
|
||||||
|
date: new Date(account?.created_at!).toLocaleDateString('zh-CN', {
|
||||||
year: 'numeric',
|
year: 'numeric',
|
||||||
month: 'long',
|
month: 'long',
|
||||||
day: 'numeric'
|
day: 'numeric'
|
||||||
})
|
})
|
||||||
})}
|
} || null
|
||||||
</Text>
|
)}
|
||||||
</View>
|
</Text>
|
||||||
)}
|
</View>
|
||||||
|
|
||||||
<View style={styles.summary}>
|
<View style={styles.summary}>
|
||||||
<Text style={{ color: theme.primary }}>
|
<Text style={{ color: theme.primary }}>
|
||||||
{t('content.summary.statuses_count', {
|
{t('content.summary.statuses_count', {
|
||||||
count: account?.statuses_count
|
count: account?.statuses_count || 0
|
||||||
})}
|
})}
|
||||||
</Text>
|
</Text>
|
||||||
<Text style={{ color: theme.primary }}>
|
<Text style={{ color: theme.primary, textAlign: 'center' }}>
|
||||||
{t('content.summary.followers_count', {
|
{t('content.summary.followers_count', {
|
||||||
count: account?.followers_count
|
count: account?.followers_count || 0
|
||||||
})}
|
})}
|
||||||
</Text>
|
</Text>
|
||||||
<Text style={{ color: theme.primary }}>
|
<Text style={{ color: theme.primary, textAlign: 'right' }}>
|
||||||
{t('content.summary.following_count', {
|
{t('content.summary.following_count', {
|
||||||
count: account?.following_count
|
count: account?.following_count || 0
|
||||||
})}
|
})}
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
|
@ -136,26 +197,40 @@ const styles = StyleSheet.create({
|
||||||
borderRadius: 8
|
borderRadius: 8
|
||||||
},
|
},
|
||||||
display_name: {
|
display_name: {
|
||||||
fontSize: StyleConstants.Font.Size.L,
|
flexDirection: 'row',
|
||||||
fontWeight: StyleConstants.Font.Weight.Bold,
|
|
||||||
marginTop: StyleConstants.Spacing.M,
|
marginTop: StyleConstants.Spacing.M,
|
||||||
marginBottom: StyleConstants.Spacing.XS
|
marginBottom: StyleConstants.Spacing.XS
|
||||||
},
|
},
|
||||||
account: {
|
account: {
|
||||||
fontSize: StyleConstants.Font.Size.M,
|
flexDirection: 'row',
|
||||||
marginBottom: StyleConstants.Spacing.S
|
alignItems: 'center',
|
||||||
|
marginBottom: StyleConstants.Spacing.L
|
||||||
},
|
},
|
||||||
|
account_types: { marginLeft: StyleConstants.Spacing.S },
|
||||||
fields: {
|
fields: {
|
||||||
marginBottom: StyleConstants.Spacing.S
|
borderTopWidth: 0.5,
|
||||||
|
marginBottom: StyleConstants.Spacing.M
|
||||||
|
},
|
||||||
|
field: {
|
||||||
|
flex: 1,
|
||||||
|
flexDirection: 'row',
|
||||||
|
borderBottomWidth: 0.5,
|
||||||
|
paddingTop: StyleConstants.Spacing.S,
|
||||||
|
paddingBottom: StyleConstants.Spacing.S
|
||||||
},
|
},
|
||||||
note: {
|
note: {
|
||||||
marginBottom: StyleConstants.Spacing.M
|
marginBottom: StyleConstants.Spacing.L
|
||||||
},
|
},
|
||||||
created_at: {
|
created_at: {
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
marginBottom: StyleConstants.Spacing.M
|
marginBottom: StyleConstants.Spacing.M
|
||||||
},
|
},
|
||||||
|
created_at_icon: {
|
||||||
|
marginRight: StyleConstants.Spacing.XS
|
||||||
|
},
|
||||||
summary: {
|
summary: {
|
||||||
|
flex: 1,
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
justifyContent: 'space-between'
|
justifyContent: 'space-between'
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
import { useNavigation } from '@react-navigation/native'
|
import { useNavigation } from '@react-navigation/native'
|
||||||
import React, { useRef, useState } from 'react'
|
import React, { useRef, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import { ActionSheetIOS } from 'react-native'
|
||||||
import { createNativeStackNavigator } from 'react-native-screens/native-stack'
|
import { createNativeStackNavigator } from 'react-native-screens/native-stack'
|
||||||
import { WebView } from 'react-native-webview'
|
import { WebView } from 'react-native-webview'
|
||||||
|
import BottomSheet from 'src/components/BottomSheet'
|
||||||
|
import BottomSheetRow from 'src/components/BottomSheet/Row'
|
||||||
|
|
||||||
import { HeaderLeft, HeaderRight } from 'src/components/Header'
|
import { HeaderLeft, HeaderRight } from 'src/components/Header'
|
||||||
|
|
||||||
|
@ -24,6 +27,7 @@ const ScreenSharedWebview: React.FC<Props> = ({
|
||||||
const navigation = useNavigation()
|
const navigation = useNavigation()
|
||||||
const { t } = useTranslation('sharedWebview')
|
const { t } = useTranslation('sharedWebview')
|
||||||
const [title, setTitle] = useState<string>(t('heading.loading'))
|
const [title, setTitle] = useState<string>(t('heading.loading'))
|
||||||
|
const [bottomSheet, showBottomSheet] = useState(false)
|
||||||
const webview = useRef<WebView>(null)
|
const webview = useRef<WebView>(null)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -40,19 +44,56 @@ const ScreenSharedWebview: React.FC<Props> = ({
|
||||||
),
|
),
|
||||||
headerRight: () => (
|
headerRight: () => (
|
||||||
<HeaderRight
|
<HeaderRight
|
||||||
icon='refresh-cw'
|
icon='more-horizontal'
|
||||||
onPress={() => webview.current?.reload()}
|
onPress={() => showBottomSheet(true)}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{() => (
|
{() => (
|
||||||
<WebView
|
<>
|
||||||
ref={webview}
|
<WebView
|
||||||
source={{ uri }}
|
ref={webview}
|
||||||
onLoad={({ nativeEvent }) => setTitle(nativeEvent.title)}
|
source={{ uri }}
|
||||||
onError={() => setTitle(t('heading.error'))}
|
decelerationRate='normal'
|
||||||
/>
|
onLoad={({ nativeEvent }) => setTitle(nativeEvent.title)}
|
||||||
|
onError={() => setTitle(t('heading.error'))}
|
||||||
|
/>
|
||||||
|
<BottomSheet
|
||||||
|
visible={bottomSheet}
|
||||||
|
handleDismiss={() => showBottomSheet(false)}
|
||||||
|
>
|
||||||
|
<BottomSheetRow
|
||||||
|
onPress={() => {
|
||||||
|
ActionSheetIOS.showShareActionSheetWithOptions(
|
||||||
|
{
|
||||||
|
url: uri,
|
||||||
|
excludedActivityTypes: [
|
||||||
|
'com.apple.UIKit.activity.Mail',
|
||||||
|
'com.apple.UIKit.activity.Print',
|
||||||
|
'com.apple.UIKit.activity.SaveToCameraRoll',
|
||||||
|
'com.apple.UIKit.activity.OpenInIBooks'
|
||||||
|
]
|
||||||
|
},
|
||||||
|
() => {},
|
||||||
|
() => {
|
||||||
|
showBottomSheet(false)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
icon='share'
|
||||||
|
text={'分享链接'}
|
||||||
|
/>
|
||||||
|
<BottomSheetRow
|
||||||
|
onPress={() => {
|
||||||
|
showBottomSheet(false)
|
||||||
|
webview.current?.reload()
|
||||||
|
}}
|
||||||
|
icon='refresh-cw'
|
||||||
|
text='刷新'
|
||||||
|
/>
|
||||||
|
</BottomSheet>
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
</Stack.Screen>
|
</Stack.Screen>
|
||||||
</Stack.Navigator>
|
</Stack.Navigator>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import React, { createContext, useContext, useEffect, useState } from 'react'
|
import React, { createContext, useContext, useEffect, useState } from 'react'
|
||||||
import { Appearance } from 'react-native-appearance'
|
import { useColorScheme } from 'react-native-appearance'
|
||||||
import { useSelector } from 'react-redux'
|
import { useSelector } from 'react-redux'
|
||||||
import { ColorDefinitions, getTheme } from 'src/utils/styles/themes'
|
import { ColorDefinitions, getTheme } from 'src/utils/styles/themes'
|
||||||
import { getSettingsTheme } from '../slices/settingsSlice'
|
import { getSettingsTheme } from '../slices/settingsSlice'
|
||||||
|
@ -19,11 +19,10 @@ export const ManageThemeContext = createContext<ContextType>({
|
||||||
export const useTheme = () => useContext(ManageThemeContext)
|
export const useTheme = () => useContext(ManageThemeContext)
|
||||||
|
|
||||||
const ThemeManager: React.FC = ({ children }) => {
|
const ThemeManager: React.FC = ({ children }) => {
|
||||||
|
const osTheme = useColorScheme()
|
||||||
const userTheme = useSelector(getSettingsTheme)
|
const userTheme = useSelector(getSettingsTheme)
|
||||||
const currentMode =
|
const currentMode =
|
||||||
userTheme === 'auto'
|
userTheme === 'auto' ? (osTheme as 'light' | 'dark') : userTheme
|
||||||
? (Appearance.getColorScheme() as 'light' | 'dark')
|
|
||||||
: userTheme
|
|
||||||
|
|
||||||
const [mode, setMode] = useState(currentMode)
|
const [mode, setMode] = useState(currentMode)
|
||||||
|
|
||||||
|
|
|
@ -4,9 +4,10 @@ export const StyleConstants = {
|
||||||
Font: {
|
Font: {
|
||||||
Size: {
|
Size: {
|
||||||
S: 12,
|
S: 12,
|
||||||
M: 14,
|
M: 16,
|
||||||
L: 18
|
L: 18
|
||||||
},
|
},
|
||||||
|
LineHeight: { M: 20 },
|
||||||
Weight: {
|
Weight: {
|
||||||
Bold: '600' as '600'
|
Bold: '600' as '600'
|
||||||
}
|
}
|
||||||
|
@ -19,7 +20,7 @@ export const StyleConstants = {
|
||||||
L: Base * 6,
|
L: Base * 6,
|
||||||
XL: Base * 10,
|
XL: Base * 10,
|
||||||
Global: {
|
Global: {
|
||||||
PagePadding: Base * 6
|
PagePadding: Base * 4
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue