diff --git a/package.json b/package.json index 0c4fa422..acb70572 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "expo-firebase-analytics": "~2.6.0", "expo-firebase-core": "~1.3.0", "expo-gl": "~9.2.0", + "expo-haptics": "~8.4.0", "expo-image-picker": "~9.2.0", "expo-linear-gradient": "~8.4.0", "expo-linking": "~2.0.0", diff --git a/src/Index.tsx b/src/Index.tsx index 9c930f02..3ed15602 100644 --- a/src/Index.tsx +++ b/src/Index.tsx @@ -202,7 +202,7 @@ const Index: React.FC = ({ localCorrupt }) => { inactiveTintColor: localInstance ? theme.secondary : theme.disabled, showLabel: false }), - [] + [theme, localInstance] ) const tabScreenLocalListeners = useCallback( () => ({ @@ -212,7 +212,7 @@ const Index: React.FC = ({ localCorrupt }) => { } } }), - [] + [localInstance] ) const tabScreenComposeListeners = useCallback( ({ navigation }) => ({ @@ -223,7 +223,7 @@ const Index: React.FC = ({ localCorrupt }) => { } } }), - [] + [localInstance] ) const tabScreenComposeComponent = useCallback(() => null, []) const tabScreenNotificationsListeners = useCallback( @@ -234,7 +234,7 @@ const Index: React.FC = ({ localCorrupt }) => { } } }), - [] + [localInstance] ) const tabScreenNotificationsOptions = useMemo( () => ({ @@ -244,7 +244,7 @@ const Index: React.FC = ({ localCorrupt }) => { backgroundColor: theme.red } }), - [] + [theme, prevNotification] ) return ( diff --git a/src/components/ParseContent.tsx b/src/components/ParseContent.tsx index e555acaa..f0fbc1fc 100644 --- a/src/components/ParseContent.tsx +++ b/src/components/ParseContent.tsx @@ -77,7 +77,7 @@ const renderNode = ({ } else { const domain = href.split(new RegExp(/:\/\/(.[^\/]+)/)) // Need example here - const content = node.children && node.children[0].data + const content = node.children && node.children[0] && node.children[0].data const shouldBeTag = tags && tags.filter(tag => `#${tag.name}` === content).length > 0 return ( diff --git a/src/components/Timelines/Timeline/Default.tsx b/src/components/Timelines/Timeline/Default.tsx index e4843e00..0e7c65c1 100644 --- a/src/components/Timelines/Timeline/Default.tsx +++ b/src/components/Timelines/Timeline/Default.tsx @@ -1,7 +1,3 @@ -import React, { useCallback } from 'react' -import { Dimensions, Pressable, StyleSheet, View } from 'react-native' -import { useNavigation } from '@react-navigation/native' - import TimelineActioned from '@components/Timelines/Timeline/Shared/Actioned' import TimelineActions from '@components/Timelines/Timeline/Shared/Actions' import TimelineAttachment from '@components/Timelines/Timeline/Shared/Attachment' @@ -10,10 +6,12 @@ import TimelineCard from '@components/Timelines/Timeline/Shared/Card' import TimelineContent from '@components/Timelines/Timeline/Shared/Content' import TimelineHeaderDefault from '@components/Timelines/Timeline/Shared/HeaderDefault' import TimelinePoll from '@components/Timelines/Timeline/Shared/Poll' - +import { useNavigation } from '@react-navigation/native' +import { getLocalAccountId } from '@utils/slices/instancesSlice' import { StyleConstants } from '@utils/styles/constants' +import React, { useCallback } from 'react' +import { Pressable, StyleSheet, View } from 'react-native' import { useSelector } from 'react-redux' -import { getLocalAccountId } from '@root/utils/slices/instancesSlice' export interface Props { item: Mastodon.Status @@ -36,13 +34,6 @@ const TimelineDefault: React.FC = ({ const navigation = useNavigation() let actualStatus = item.reblog ? item.reblog : item - const contentWidth = highlighted - ? Dimensions.get('window').width - - StyleConstants.Spacing.Global.PagePadding * 2 // Global page padding on both sides - : Dimensions.get('window').width - - StyleConstants.Spacing.Global.PagePadding * 2 - // Global page padding on both sides - StyleConstants.Avatar.M - // Avatar width - StyleConstants.Spacing.S // Avatar margin to the right const onPress = useCallback( () => @@ -93,10 +84,7 @@ const TimelineDefault: React.FC = ({ /> )} {actualStatus.media_attachments.length > 0 && ( - + )} {actualStatus.card && } diff --git a/src/components/Timelines/Timeline/Notifications.tsx b/src/components/Timelines/Timeline/Notifications.tsx index 483da776..f0807b32 100644 --- a/src/components/Timelines/Timeline/Notifications.tsx +++ b/src/components/Timelines/Timeline/Notifications.tsx @@ -1,7 +1,3 @@ -import React, { useCallback } from 'react' -import { Dimensions, Pressable, StyleSheet, View } from 'react-native' -import { useNavigation } from '@react-navigation/native' - import TimelineActioned from '@components/Timelines/Timeline/Shared/Actioned' import TimelineActions from '@components/Timelines/Timeline/Shared/Actions' import TimelineAttachment from '@components/Timelines/Timeline/Shared/Attachment' @@ -10,10 +6,12 @@ import TimelineCard from '@components/Timelines/Timeline/Shared/Card' import TimelineContent from '@components/Timelines/Timeline/Shared/Content' import TimelineHeaderNotification from '@components/Timelines/Timeline/Shared/HeaderNotification' import TimelinePoll from '@components/Timelines/Timeline/Shared/Poll' - +import { useNavigation } from '@react-navigation/native' +import { getLocalAccountId } from '@utils/slices/instancesSlice' import { StyleConstants } from '@utils/styles/constants' +import React, { useCallback } from 'react' +import { Pressable, StyleSheet, View } from 'react-native' import { useSelector } from 'react-redux' -import { getLocalAccountId } from '@root/utils/slices/instancesSlice' export interface Props { notification: Mastodon.Notification @@ -31,13 +29,6 @@ const TimelineNotifications: React.FC = ({ const actualAccount = notification.status ? notification.status.account : notification.account - const contentWidth = highlighted - ? Dimensions.get('window').width - - StyleConstants.Spacing.Global.PagePadding * 2 // Global page padding on both sides - : Dimensions.get('window').width - - StyleConstants.Spacing.Global.PagePadding * 2 - // Global page padding on both sides - StyleConstants.Avatar.M - // Avatar width - StyleConstants.Spacing.S // Avatar margin to the right const onPress = useCallback( () => @@ -92,10 +83,7 @@ const TimelineNotifications: React.FC = ({ /> )} {notification.status.media_attachments.length > 0 && ( - + )} {notification.status.card && ( diff --git a/src/components/Timelines/Timeline/Shared/Actions.tsx b/src/components/Timelines/Timeline/Shared/Actions.tsx index 451243c6..d85f20d1 100644 --- a/src/components/Timelines/Timeline/Shared/Actions.tsx +++ b/src/components/Timelines/Timeline/Shared/Actions.tsx @@ -10,6 +10,7 @@ import { StyleConstants } from '@utils/styles/constants' import { useNavigation } from '@react-navigation/native' import { findIndex } from 'lodash' import { TimelineData } from '../../Timeline' +import haptics from '@root/components/haptics' const fireMutation = async ({ id, @@ -110,12 +111,14 @@ const TimelineActions: React.FC = ({ queryKey, status, reblog }) => { return old }) + haptics('Success') break } return oldData }, onError: (err, _, oldData) => { + haptics('Error') toast({ type: 'error', content: '请重试' }) queryClient.setQueryData(queryKey, oldData) } @@ -172,8 +175,8 @@ const TimelineActions: React.FC = ({ queryKey, status, reblog }) => { 'com.apple.UIKit.activity.OpenInIBooks' ] }, - () => {}, - () => {} + () => haptics('Success'), + () => haptics('Error') ), [] ) diff --git a/src/components/Timelines/Timeline/Shared/Attachment.tsx b/src/components/Timelines/Timeline/Shared/Attachment.tsx index 011c8f3d..60ec7344 100644 --- a/src/components/Timelines/Timeline/Shared/Attachment.tsx +++ b/src/components/Timelines/Timeline/Shared/Attachment.tsx @@ -1,29 +1,30 @@ +import Button from '@components/Button' +import AttachmentAudio from '@components/Timelines/Timeline/Shared/Attachment/Audio' +import AttachmentImage from '@components/Timelines/Timeline/Shared/Attachment/Image' +import AttachmentUnsupported from '@components/Timelines/Timeline/Shared/Attachment/Unsupported' +import AttachmentVideo from '@components/Timelines/Timeline/Shared/Attachment/Video' +import { useNavigation } from '@react-navigation/native' +import haptics from '@root/components/haptics' +import { StyleConstants } from '@utils/styles/constants' +import layoutAnimation from '@utils/styles/layoutAnimation' import React, { useCallback, useMemo, useState } from 'react' import { Pressable, StyleSheet, View } from 'react-native' -import { StyleConstants } from '@utils/styles/constants' -import { useTheme } from '@utils/styles/ThemeManager' - -import AttachmentImage from '@root/components/Timelines/Timeline/Shared/Attachment/Image' -import AttachmentVideo from '@root/components/Timelines/Timeline/Shared/Attachment/Video' import { IImageInfo } from 'react-native-image-zoom-viewer/built/image-viewer.type' -import { useNavigation } from '@react-navigation/native' -import AttachmentUnsupported from './Attachment/Unsupported' -import AttachmentAudio from './Attachment/Audio' -import layoutAnimation from '@root/utils/styles/layoutAnimation' -import Button from '@root/components/Button' export interface Props { status: Pick - contentWidth: number } -const TimelineAttachment: React.FC = ({ status, contentWidth }) => { - const { theme } = useTheme() - +const TimelineAttachment: React.FC = ({ status }) => { const [sensitiveShown, setSensitiveShown] = useState(status.sensitive) const onPressBlurView = useCallback(() => { layoutAnimation() setSensitiveShown(false) + haptics('Medium') + }, []) + const onPressShow = useCallback(() => { + setSensitiveShown(true) + haptics('Medium') }, []) let imageUrls: (IImageInfo & { @@ -65,8 +66,6 @@ const TimelineAttachment: React.FC = ({ status, contentWidth }) => { key={index} sensitiveShown={sensitiveShown} video={attachment} - width={contentWidth} - height={(contentWidth / 16) * 9} /> ) case 'gifv': @@ -75,8 +74,6 @@ const TimelineAttachment: React.FC = ({ status, contentWidth }) => { key={index} sensitiveShown={sensitiveShown} video={attachment} - width={contentWidth} - height={(contentWidth / 16) * 9} /> ) case 'audio': @@ -88,7 +85,13 @@ const TimelineAttachment: React.FC = ({ status, contentWidth }) => { /> ) default: - return + return ( + + ) } }), [sensitiveShown] @@ -114,7 +117,7 @@ const TimelineAttachment: React.FC = ({ status, contentWidth }) => { content='eye-off' round overlay - onPress={() => setSensitiveShown(!sensitiveShown)} + onPress={onPressShow} style={{ position: 'absolute', top: StyleConstants.Spacing.S, diff --git a/src/components/Timelines/Timeline/Shared/Attachment/Unsupported.tsx b/src/components/Timelines/Timeline/Shared/Attachment/Unsupported.tsx index dbdf8b32..586a4c52 100644 --- a/src/components/Timelines/Timeline/Shared/Attachment/Unsupported.tsx +++ b/src/components/Timelines/Timeline/Shared/Attachment/Unsupported.tsx @@ -8,10 +8,14 @@ import React from 'react' import { StyleSheet, Text, View } from 'react-native' export interface Props { + sensitiveShown: boolean attachment: Mastodon.AttachmentUnknown } -const AttachmentUnsupported: React.FC = ({ attachment }) => { +const AttachmentUnsupported: React.FC = ({ + sensitiveShown, + attachment +}) => { const { theme } = useTheme() return ( @@ -26,22 +30,26 @@ const AttachmentUnsupported: React.FC = ({ attachment }) => { ) : null} - - 文件不支持 - - {attachment.remote_url ? ( -