mirror of
https://github.com/tooot-app/app
synced 2025-06-05 22:19:13 +02:00
Updates
This commit is contained in:
@ -13,61 +13,59 @@ export interface Props {
|
||||
fontBold?: boolean
|
||||
}
|
||||
|
||||
const ParseEmojis: React.FC<Props> = ({
|
||||
content,
|
||||
emojis,
|
||||
size = 'M',
|
||||
fontBold = false
|
||||
}) => {
|
||||
const { mode, theme } = useTheme()
|
||||
const styles = useMemo(() => {
|
||||
return StyleSheet.create({
|
||||
text: {
|
||||
color: theme.primary,
|
||||
...StyleConstants.FontStyle[size],
|
||||
...(fontBold && { fontWeight: StyleConstants.Font.Weight.Bold })
|
||||
},
|
||||
image: {
|
||||
width: StyleConstants.Font.Size[size],
|
||||
height: StyleConstants.Font.Size[size],
|
||||
transform: [{ translateY: size === 'L' ? -3 : -1 }]
|
||||
}
|
||||
})
|
||||
}, [mode])
|
||||
const ParseEmojis = React.memo(
|
||||
({ content, emojis, size = 'M', fontBold = false }: Props) => {
|
||||
const { mode, theme } = useTheme()
|
||||
const styles = useMemo(() => {
|
||||
return StyleSheet.create({
|
||||
text: {
|
||||
color: theme.primary,
|
||||
...StyleConstants.FontStyle[size],
|
||||
...(fontBold && { fontWeight: StyleConstants.Font.Weight.Bold })
|
||||
},
|
||||
image: {
|
||||
width: StyleConstants.Font.Size[size],
|
||||
height: StyleConstants.Font.Size[size],
|
||||
transform: [{ translateY: size === 'L' ? -3 : -1 }]
|
||||
}
|
||||
})
|
||||
}, [mode])
|
||||
|
||||
return (
|
||||
<Text style={styles.text}>
|
||||
{emojis ? (
|
||||
content
|
||||
.split(regexEmoji)
|
||||
.filter(f => f)
|
||||
.map((str, i) => {
|
||||
if (str.match(regexEmoji)) {
|
||||
const emojiShortcode = str.split(regexEmoji)[1]
|
||||
const emojiIndex = emojis.findIndex(emoji => {
|
||||
return emojiShortcode === `:${emoji.shortcode}:`
|
||||
})
|
||||
return emojiIndex === -1 ? (
|
||||
<Text key={i}>{emojiShortcode}</Text>
|
||||
) : (
|
||||
<Text key={i}>
|
||||
{/* When emoji starts a paragraph, lineHeight will break */}
|
||||
{i === 0 ? <Text> </Text> : null}
|
||||
<FastImage
|
||||
source={{ uri: emojis[emojiIndex].url }}
|
||||
style={styles.image}
|
||||
/>
|
||||
</Text>
|
||||
)
|
||||
} else {
|
||||
return <Text key={i}>{str}</Text>
|
||||
}
|
||||
})
|
||||
) : (
|
||||
<Text>{content}</Text>
|
||||
)}
|
||||
</Text>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<Text style={styles.text}>
|
||||
{emojis ? (
|
||||
content
|
||||
.split(regexEmoji)
|
||||
.filter(f => f)
|
||||
.map((str, i) => {
|
||||
if (str.match(regexEmoji)) {
|
||||
const emojiShortcode = str.split(regexEmoji)[1]
|
||||
const emojiIndex = emojis.findIndex(emoji => {
|
||||
return emojiShortcode === `:${emoji.shortcode}:`
|
||||
})
|
||||
return emojiIndex === -1 ? (
|
||||
<Text key={i}>{emojiShortcode}</Text>
|
||||
) : (
|
||||
<Text key={i}>
|
||||
{/* When emoji starts a paragraph, lineHeight will break */}
|
||||
{i === 0 ? <Text> </Text> : null}
|
||||
<FastImage
|
||||
source={{ uri: emojis[emojiIndex].url }}
|
||||
style={styles.image}
|
||||
/>
|
||||
</Text>
|
||||
)
|
||||
} else {
|
||||
return <Text key={i}>{str}</Text>
|
||||
}
|
||||
})
|
||||
) : (
|
||||
<Text>{content}</Text>
|
||||
)}
|
||||
</Text>
|
||||
)
|
||||
},
|
||||
(prev, next) => prev.content === next.content
|
||||
)
|
||||
|
||||
export default React.memo(ParseEmojis, () => true)
|
||||
export default ParseEmojis
|
||||
|
@ -30,8 +30,8 @@ const renderNode = ({
|
||||
theme: any
|
||||
node: any
|
||||
index: number
|
||||
size: 'M' | 'L'
|
||||
navigation: StackNavigationProp<Nav.LocalStackParamList>
|
||||
size: 'S' | 'M' | 'L'
|
||||
navigation: StackNavigationProp<Nav.TabLocalStackParamList>
|
||||
mentions?: Mastodon.Mention[]
|
||||
tags?: Mastodon.Tag[]
|
||||
showFullLink: boolean
|
||||
@ -145,7 +145,7 @@ const renderNode = ({
|
||||
|
||||
export interface Props {
|
||||
content: string
|
||||
size?: 'M' | 'L'
|
||||
size?: 'S' | 'M' | 'L'
|
||||
emojis?: Mastodon.Emoji[]
|
||||
mentions?: Mastodon.Mention[]
|
||||
tags?: Mastodon.Tag[]
|
||||
@ -167,7 +167,7 @@ const ParseHTML: React.FC<Props> = ({
|
||||
disableDetails = false
|
||||
}) => {
|
||||
const navigation = useNavigation<
|
||||
StackNavigationProp<Nav.LocalStackParamList>
|
||||
StackNavigationProp<Nav.TabLocalStackParamList>
|
||||
>()
|
||||
const route = useRoute()
|
||||
const { theme } = useTheme()
|
||||
|
@ -82,11 +82,10 @@ const Timeline: React.FC<Props> = ({
|
||||
const navigation = useNavigation()
|
||||
useEffect(() => {
|
||||
const unsubscribe = navigation.addListener('focus', props => {
|
||||
if (props.target && props.target.includes('Screen-Notifications-Root')) {
|
||||
if (props.target && props.target.includes('Tab-Notifications-Root')) {
|
||||
if (flattenData.length) {
|
||||
dispatch(
|
||||
localUpdateNotification({
|
||||
unread: false,
|
||||
latestTime: (flattenData[0] as Mastodon.Notification).created_at
|
||||
})
|
||||
)
|
||||
|
@ -47,6 +47,6 @@ export default {
|
||||
heading: 'Help us improve',
|
||||
description: 'Collecting only non-user relative usage'
|
||||
},
|
||||
version: 'Version v{{version}}'
|
||||
version: 'Version v{{version}} ({{releaseChannel}})'
|
||||
}
|
||||
}
|
||||
|
@ -47,6 +47,6 @@ export default {
|
||||
heading: '帮助我们改进',
|
||||
description: '收集不与用户相关联的使用信息'
|
||||
},
|
||||
version: '版本 v{{version}}'
|
||||
version: '版本 v{{version}} ({{releaseChannel}})'
|
||||
}
|
||||
}
|
||||
|
@ -90,7 +90,7 @@ const ScreenTabs: React.FC<ScreenTabsProp> = ({ navigation }) => {
|
||||
}),
|
||||
[localActiveIndex, localAccount]
|
||||
)
|
||||
const tabNavigatorTabBarOptions = useMemo(
|
||||
const tabBarOptions = useMemo(
|
||||
() => ({
|
||||
activeTintColor: theme.primary,
|
||||
inactiveTintColor:
|
||||
@ -100,7 +100,7 @@ const ScreenTabs: React.FC<ScreenTabsProp> = ({ navigation }) => {
|
||||
}),
|
||||
[theme, localActiveIndex]
|
||||
)
|
||||
const tabScreenLocalListeners = useCallback(
|
||||
const localListeners = useCallback(
|
||||
() => ({
|
||||
tabPress: (e: any) => {
|
||||
if (!(localActiveIndex !== null)) {
|
||||
@ -110,7 +110,7 @@ const ScreenTabs: React.FC<ScreenTabsProp> = ({ navigation }) => {
|
||||
}),
|
||||
[localActiveIndex]
|
||||
)
|
||||
const tabScreenComposeListeners = useMemo(
|
||||
const composeListeners = useMemo(
|
||||
() => ({
|
||||
tabPress: (e: any) => {
|
||||
e.preventDefault()
|
||||
@ -122,8 +122,8 @@ const ScreenTabs: React.FC<ScreenTabsProp> = ({ navigation }) => {
|
||||
}),
|
||||
[localActiveIndex]
|
||||
)
|
||||
const tabScreenComposeComponent = useCallback(() => null, [])
|
||||
const tabScreenNotificationsListeners = useCallback(
|
||||
const composeComponent = useCallback(() => null, [])
|
||||
const notificationsListeners = useCallback(
|
||||
() => ({
|
||||
tabPress: (e: any) => {
|
||||
if (!(localActiveIndex !== null)) {
|
||||
@ -144,66 +144,67 @@ const ScreenTabs: React.FC<ScreenTabsProp> = ({ navigation }) => {
|
||||
}
|
||||
})
|
||||
const prevNotification = useSelector(getLocalNotification)
|
||||
useEffect(() => {
|
||||
if (queryNotification.data?.pages) {
|
||||
const flattenData = queryNotification.data.pages.flatMap(d => [...d])
|
||||
const latestNotificationTime = flattenData.length
|
||||
? (flattenData[0] as Mastodon.Notification).created_at
|
||||
: undefined
|
||||
const notificationsOptions = useMemo(() => {
|
||||
const badge = {
|
||||
show: {
|
||||
tabBarBadge: '',
|
||||
tabBarBadgeStyle: {
|
||||
transform: [{ scale: 0.5 }],
|
||||
backgroundColor: theme.red
|
||||
}
|
||||
},
|
||||
hide: {
|
||||
tabBarBadgeStyle: {
|
||||
transform: [{ scale: 0.5 }],
|
||||
backgroundColor: theme.red
|
||||
}
|
||||
}
|
||||
}
|
||||
const flattenData = queryNotification.data?.pages.flatMap(d => [...d])
|
||||
const latestNotificationTime = flattenData?.length
|
||||
? (flattenData[0] as Mastodon.Notification).created_at
|
||||
: undefined
|
||||
|
||||
if (!prevNotification || !prevNotification.latestTime) {
|
||||
dispatch(localUpdateNotification({ unread: false }))
|
||||
} else if (
|
||||
if (prevNotification?.latestTime) {
|
||||
if (
|
||||
latestNotificationTime &&
|
||||
new Date(prevNotification.latestTime) < new Date(latestNotificationTime)
|
||||
) {
|
||||
dispatch(
|
||||
localUpdateNotification({
|
||||
unread: true,
|
||||
latestTime: latestNotificationTime
|
||||
})
|
||||
)
|
||||
return badge.show
|
||||
} else {
|
||||
return badge.hide
|
||||
}
|
||||
} else {
|
||||
if (latestNotificationTime) {
|
||||
return badge.show
|
||||
} else {
|
||||
return badge.hide
|
||||
}
|
||||
}
|
||||
}, [queryNotification.data?.pages])
|
||||
}, [prevNotification, queryNotification.data?.pages])
|
||||
|
||||
return (
|
||||
<Tab.Navigator
|
||||
initialRouteName={localActiveIndex !== null ? 'Tab-Local' : 'Tab-Me'}
|
||||
screenOptions={screenOptions}
|
||||
tabBarOptions={tabNavigatorTabBarOptions}
|
||||
tabBarOptions={tabBarOptions}
|
||||
>
|
||||
<Tab.Screen
|
||||
name='Tab-Local'
|
||||
component={TabLocal}
|
||||
listeners={tabScreenLocalListeners}
|
||||
listeners={localListeners}
|
||||
/>
|
||||
<Tab.Screen name='Tab-Public' component={TabPublic} />
|
||||
<Tab.Screen
|
||||
name='Tab-Compose'
|
||||
component={tabScreenComposeComponent}
|
||||
listeners={tabScreenComposeListeners}
|
||||
component={composeComponent}
|
||||
listeners={composeListeners}
|
||||
/>
|
||||
<Tab.Screen
|
||||
name='Tab-Notifications'
|
||||
component={TabNotifications}
|
||||
listeners={tabScreenNotificationsListeners}
|
||||
options={
|
||||
prevNotification && prevNotification.unread
|
||||
? {
|
||||
tabBarBadge: '',
|
||||
tabBarBadgeStyle: {
|
||||
transform: [{ scale: 0.5 }],
|
||||
backgroundColor: theme.red
|
||||
}
|
||||
}
|
||||
: {
|
||||
tabBarBadgeStyle: {
|
||||
transform: [{ scale: 0.5 }],
|
||||
backgroundColor: theme.red
|
||||
}
|
||||
}
|
||||
}
|
||||
listeners={notificationsListeners}
|
||||
options={notificationsOptions}
|
||||
/>
|
||||
<Tab.Screen name='Tab-Me' component={TabMe} />
|
||||
</Tab.Navigator>
|
||||
|
@ -29,7 +29,10 @@ const SettingsAnalytics: React.FC = () => {
|
||||
}
|
||||
/>
|
||||
<Text style={[styles.version, { color: theme.secondary }]}>
|
||||
{t('content.version', { version: Constants.manifest.version })}
|
||||
{t('content.version', {
|
||||
version: Constants.manifest.version,
|
||||
releaseChannel: Constants.manifest.releaseChannel || 'dev'
|
||||
})}
|
||||
</Text>
|
||||
</MenuContainer>
|
||||
)
|
||||
|
@ -75,7 +75,7 @@ const AccountInformation: React.FC<Props> = ({ account, myInfo = false }) => {
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
base: {
|
||||
marginTop: -StyleConstants.Spacing.Global.PagePadding * 3,
|
||||
marginTop: -StyleConstants.Avatar.L / 2,
|
||||
padding: StyleConstants.Spacing.Global.PagePadding
|
||||
},
|
||||
avatarAndActions: {
|
||||
|
@ -25,7 +25,7 @@ const AccountInformationFields = React.memo(
|
||||
>
|
||||
<ParseHTML
|
||||
content={field.name}
|
||||
size={'M'}
|
||||
size={'S'}
|
||||
emojis={account.emojis}
|
||||
showFullLink
|
||||
numberOfLines={5}
|
||||
@ -42,7 +42,7 @@ const AccountInformationFields = React.memo(
|
||||
<View style={styles.fieldRight}>
|
||||
<ParseHTML
|
||||
content={field.value}
|
||||
size={'M'}
|
||||
size={'S'}
|
||||
emojis={account.emojis}
|
||||
showFullLink
|
||||
numberOfLines={5}
|
||||
|
@ -20,7 +20,6 @@ export type InstanceLocal = {
|
||||
preferences: Mastodon.Preferences
|
||||
}
|
||||
notification: {
|
||||
unread: boolean
|
||||
latestTime?: Mastodon.Notification['created_at']
|
||||
}
|
||||
}
|
||||
@ -115,7 +114,7 @@ export const localAddInstance = createAsyncThunk(
|
||||
preferences
|
||||
},
|
||||
notification: {
|
||||
unread: false
|
||||
latestTime: undefined
|
||||
}
|
||||
}
|
||||
})
|
||||
@ -203,10 +202,8 @@ const instancesSlice = createSlice({
|
||||
state,
|
||||
action: PayloadAction<Partial<InstanceLocal['notification']>>
|
||||
) => {
|
||||
state.local.instances[state.local.activeIndex!].notification = {
|
||||
...state.local.instances[state.local.activeIndex!].notification,
|
||||
...action.payload
|
||||
}
|
||||
state.local.instances[state.local.activeIndex!].notification =
|
||||
action.payload
|
||||
},
|
||||
remoteUpdate: (
|
||||
state,
|
||||
|
Reference in New Issue
Block a user