diff --git a/package.json b/package.json index 25d31788..76fb92c1 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "expo": "~39.0.4", "expo-auth-session": "~2.0.0", "expo-av": "~8.6.0", + "expo-blur": "~8.2.0", "expo-image-picker": "~9.1.1", "expo-linear-gradient": "~8.3.0", "expo-localization": "^9.0.0", diff --git a/src/@types/mastodon.d.ts b/src/@types/mastodon.d.ts index 7139bcb6..b8131fe3 100644 --- a/src/@types/mastodon.d.ts +++ b/src/@types/mastodon.d.ts @@ -48,10 +48,10 @@ declare namespace Mastodon { // Others remote_url?: string text_url?: string - meta: { - original: { width: number; height: number; size: string; aspect: number } - small: { width: number; height: number; size: string; aspect: number } - focus: + meta?: { + original?: { width: number; height: number; size: string; aspect: number } + small?: { width: number; height: number; size: string; aspect: number } + focus?: | { x: number; y: number } | { length: string diff --git a/src/components/BottomSheet.tsx b/src/components/BottomSheet.tsx index 5a71c234..032ef619 100644 --- a/src/components/BottomSheet.tsx +++ b/src/components/BottomSheet.tsx @@ -103,7 +103,6 @@ const styles = StyleSheet.create({ justifyContent: 'flex-end' }, container: { - padding: StyleConstants.Spacing.L, paddingTop: StyleConstants.Spacing.M }, handle: { @@ -115,9 +114,10 @@ const styles = StyleSheet.create({ }, cancel: { padding: StyleConstants.Spacing.S, + marginLeft: StyleConstants.Spacing.L, + marginRight: StyleConstants.Spacing.L, borderWidth: 1, - borderRadius: 100, - // marginBottom: StyleConstants.Spacing.L + borderRadius: 100 }, text: { fontSize: StyleConstants.Font.Size.L, diff --git a/src/components/BottomSheet/Row.tsx b/src/components/BottomSheet/Row.tsx deleted file mode 100644 index 26b55d77..00000000 --- a/src/components/BottomSheet/Row.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import React from 'react' -import { Pressable, StyleSheet, Text } from 'react-native' -import { Feather } from '@expo/vector-icons' - -import { useTheme } from 'src/utils/styles/ThemeManager' -import { StyleConstants } from 'src/utils/styles/constants' - -export interface Props { - onPress: () => void - icon: string - text: string -} - -const BottomSheetRow: React.FC = ({ onPress, icon, text }) => { - const { theme } = useTheme() - - return ( - - - {text} - - ) -} - -const styles = StyleSheet.create({ - pressable: { - width: '100%', - flexDirection: 'row', - marginBottom: StyleConstants.Spacing.L - }, - text: { - fontSize: StyleConstants.Font.Size.M, - lineHeight: StyleConstants.Font.Size.L, - marginLeft: StyleConstants.Spacing.S - } -}) - -export default BottomSheetRow diff --git a/src/components/Button.tsx b/src/components/Button.tsx new file mode 100644 index 00000000..d6a1c36b --- /dev/null +++ b/src/components/Button.tsx @@ -0,0 +1,46 @@ +import React from 'react' +import { Pressable, StyleSheet, Text } from 'react-native' +import { StyleConstants } from 'src/utils/styles/constants' +import { useTheme } from 'src/utils/styles/ThemeManager' + +export interface Props { + onPress: () => void + text: string + fontSize?: 'S' | 'M' | 'L' +} + +const Button: React.FC = ({ onPress, text, fontSize = 'M' }) => { + const { theme } = useTheme() + + return ( + + + {text} + + + ) +} + +const styles = StyleSheet.create({ + button: { + paddingTop: StyleConstants.Spacing.S, + paddingBottom: StyleConstants.Spacing.S, + paddingLeft: StyleConstants.Spacing.M, + paddingRight: StyleConstants.Spacing.M, + borderWidth: 1, + borderRadius: 100 + }, + text: { + textAlign: 'center' + } +}) + +export default Button diff --git a/src/components/Header/Left.tsx b/src/components/Header/Left.tsx index 1f0eecac..a56575c0 100644 --- a/src/components/Header/Left.tsx +++ b/src/components/Header/Left.tsx @@ -34,7 +34,7 @@ const styles = StyleSheet.create({ paddingRight: StyleConstants.Spacing.S }, text: { - fontSize: StyleConstants.Font.Size.L + fontSize: StyleConstants.Font.Size.M } }) diff --git a/src/components/Header/Right.tsx b/src/components/Header/Right.tsx index fab8b5e9..d03f6e38 100644 --- a/src/components/Header/Right.tsx +++ b/src/components/Header/Right.tsx @@ -6,6 +6,7 @@ import { useTheme } from 'src/utils/styles/ThemeManager' import { StyleConstants } from 'src/utils/styles/constants' type PropsBase = { + disabled?: boolean onPress: () => void } @@ -20,6 +21,7 @@ export interface PropsIcon extends PropsBase { } const HeaderRight: React.FC = ({ + disabled, onPress, text, icon @@ -27,12 +29,21 @@ const HeaderRight: React.FC = ({ const { theme } = useTheme() return ( - - {text && {text}} + + {text && ( + + {text} + + )} {icon && ( )} @@ -45,7 +56,7 @@ const styles = StyleSheet.create({ paddingLeft: StyleConstants.Spacing.S }, text: { - fontSize: StyleConstants.Font.Size.L + fontSize: StyleConstants.Font.Size.M } }) diff --git a/src/components/Menu.tsx b/src/components/Menu.tsx index 477e8c3f..08e76a9f 100644 --- a/src/components/Menu.tsx +++ b/src/components/Menu.tsx @@ -1,5 +1,5 @@ import MenuContainer from './Menu/Container' import MenuHeader from './Menu/Header' -import MenuItem from './Menu/Item' +import MenuRow from './Menu/Row' -export { MenuContainer, MenuHeader, MenuItem } +export { MenuContainer, MenuHeader, MenuRow } diff --git a/src/components/Menu/Container.tsx b/src/components/Menu/Container.tsx index 132bc77c..aaf001f2 100644 --- a/src/components/Menu/Container.tsx +++ b/src/components/Menu/Container.tsx @@ -1,36 +1,36 @@ -import React from 'react' +import React, { Children } from 'react' import { StyleSheet, View } from 'react-native' import { useTheme } from 'src/utils/styles/ThemeManager' import { StyleConstants } from 'src/utils/styles/constants' export interface Props { children: React.ReactNode - marginTop?: boolean } -const MenuContainer: React.FC = ({ ...props }) => { +const MenuContainer: React.FC = ({ children }) => { const { theme } = useTheme() + // @ts-ignore + const firstChild = Children.toArray(children)[0].type.name return ( - {props.children} + {children} ) } const styles = StyleSheet.create({ base: { - borderTopWidth: 1, marginBottom: StyleConstants.Spacing.L } }) diff --git a/src/components/Menu/Header.tsx b/src/components/Menu/Header.tsx index 8f42b68f..62e67570 100644 --- a/src/components/Menu/Header.tsx +++ b/src/components/Menu/Header.tsx @@ -1,19 +1,28 @@ import React from 'react' -import { StyleSheet, Text } from 'react-native' +import { StyleSheet, Text, View } from 'react-native' +import { StyleConstants } from 'src/utils/styles/constants' +import { useTheme } from 'src/utils/styles/ThemeManager' export interface Props { heading: string } const MenuHeader: React.FC = ({ heading }) => { - return {heading} + const { theme } = useTheme() + + return ( + + {heading} + + ) } const styles = StyleSheet.create({ - header: { - marginTop: 12, - paddingLeft: 12, - paddingRight: 12 + base: { + borderBottomWidth: 1, + paddingLeft: StyleConstants.Spacing.Global.PagePadding, + paddingRight: StyleConstants.Spacing.Global.PagePadding, + paddingBottom: StyleConstants.Spacing.S } }) diff --git a/src/components/Menu/Item.tsx b/src/components/Menu/Row.tsx similarity index 76% rename from src/components/Menu/Item.tsx rename to src/components/Menu/Row.tsx index be33d081..33b78f92 100644 --- a/src/components/Menu/Item.tsx +++ b/src/components/Menu/Row.tsx @@ -43,29 +43,31 @@ const Core: React.FC = ({ {title} - - {content && ( - - {content} - - )} - {iconBack && ( - - )} - + {(content || iconBack) && ( + + {content && ( + + {content} + + )} + {iconBack && ( + + )} + + )} ) } -const MenuItem: React.FC = ({ ...props }) => { +const MenuRow: React.FC = ({ ...props }) => { const { theme } = useTheme() return props.onPress ? ( @@ -95,11 +97,13 @@ const styles = StyleSheet.create({ }, front: { flex: 1, + flexBasis: '70%', flexDirection: 'row', alignItems: 'center' }, back: { flex: 1, + flexBasis: '30%', flexDirection: 'row', justifyContent: 'flex-end', alignItems: 'center' @@ -108,6 +112,7 @@ const styles = StyleSheet.create({ marginRight: 8 }, text: { + flex: 1, fontSize: StyleConstants.Font.Size.M }, content: { @@ -118,4 +123,4 @@ const styles = StyleSheet.create({ } }) -export default MenuItem +export default MenuRow diff --git a/src/components/Timelines/Timeline/Default.tsx b/src/components/Timelines/Timeline/Default.tsx index 59df9a9d..65b2f1d7 100644 --- a/src/components/Timelines/Timeline/Default.tsx +++ b/src/components/Timelines/Timeline/Default.tsx @@ -2,14 +2,15 @@ import React, { useCallback, useMemo } from 'react' import { Dimensions, Pressable, StyleSheet, View } from 'react-native' import { useNavigation } from '@react-navigation/native' -import Actioned from './Shared/Actioned' -import Avatar from './Shared/Avatar' -import HeaderDefault from './Shared/HeaderDefault' -import Content from './Shared/Content' -import Poll from './Shared/Poll' -import Attachment from './Shared/Attachment' -import Card from './Shared/Card' -import ActionsStatus from './Shared/ActionsStatus' +import TimelineActioned from './Shared/Actioned' +import TimelineActions from './Shared/Actions' +import TimelineAttachment from './Shared/Attachment' +import TimelineAvatar from './Shared/Avatar' +import TimelineCard from './Shared/Card' +import TimelineContent from './Shared/Content' +import TimelineHeaderDefault from './Shared/HeaderDefault' +import TimelinePoll from './Shared/Poll' + import { StyleConstants } from 'src/utils/styles/constants' export interface Props { @@ -22,6 +23,11 @@ const TimelineDefault: React.FC = ({ item, queryKey }) => { const navigation = useNavigation() let actualStatus = item.reblog ? item.reblog : item + const contentWidth = + Dimensions.get('window').width - + StyleConstants.Spacing.Global.PagePadding * 2 - // Global page padding on both sides + StyleConstants.Avatar.S - // Avatar width + StyleConstants.Spacing.S // Avatar margin to the right const pressableToot = useCallback( () => @@ -33,73 +39,37 @@ const TimelineDefault: React.FC = ({ item, queryKey }) => { const childrenToot = useMemo( () => ( <> - {actualStatus.content ? ( - - ) : ( - <> + {actualStatus.content.length > 0 && ( + + )} + {actualStatus.poll && ( + )} - {actualStatus.poll && } {actualStatus.media_attachments.length > 0 && ( - + )} - {actualStatus.card && } + {actualStatus.card && } ), - [] + [actualStatus.poll?.voted] ) - const statusView = useMemo(() => { - return ( - - {item.reblog && ( - - )} - - - - - {/* Can pass toot info to next page to speed up performance */} - - - + return ( + + {item.reblog && ( + + )} + + + + + {/* Can pass toot info to next page to speed up performance */} + + - ) - }, [item]) - - return statusView + + ) } const styles = StyleSheet.create({ @@ -114,8 +84,7 @@ const styles = StyleSheet.create({ flexDirection: 'row' }, details: { - flex: 1, - flexGrow: 1 + flex: 1 } }) diff --git a/src/components/Timelines/Timeline/Notifications.tsx b/src/components/Timelines/Timeline/Notifications.tsx index 78cf2455..e3296918 100644 --- a/src/components/Timelines/Timeline/Notifications.tsx +++ b/src/components/Timelines/Timeline/Notifications.tsx @@ -9,7 +9,7 @@ import Content from './Shared/Content' import Poll from './Shared/Poll' import Attachment from './Shared/Attachment' import Card from './Shared/Card' -import ActionsStatus from './Shared/ActionsStatus' +import ActionsStatus from './Shared/Actions' import { StyleConstants } from 'src/utils/styles/constants' export interface Props { diff --git a/src/components/Timelines/Timeline/Shared/Actioned.tsx b/src/components/Timelines/Timeline/Shared/Actioned.tsx index f246c3fc..6b44308a 100644 --- a/src/components/Timelines/Timeline/Shared/Actioned.tsx +++ b/src/components/Timelines/Timeline/Shared/Actioned.tsx @@ -7,19 +7,19 @@ import { useTheme } from 'src/utils/styles/ThemeManager' import { StyleConstants } from 'src/utils/styles/constants' export interface Props { + account: Mastodon.Account action: 'favourite' | 'follow' | 'mention' | 'poll' | 'reblog' - name?: string - emojis?: Mastodon.Emoji[] notification?: boolean } -const Actioned: React.FC = ({ +const TimelineActioned: React.FC = ({ + account, + action, - name, - emojis, notification = false }) => { const { theme } = useTheme() + const name = account.display_name || account.username const iconColor = theme.primary let icon @@ -74,20 +74,18 @@ const Actioned: React.FC = ({ return ( {icon} - {content ? ( + {content && ( - {emojis ? ( + {account.emojis ? ( ) : ( {content} )} - ) : ( - <> )} ) @@ -107,4 +105,4 @@ const styles = StyleSheet.create({ } }) -export default React.memo(Actioned) +export default React.memo(TimelineActioned, () => true) diff --git a/src/components/Timelines/Timeline/Shared/ActionsStatus.tsx b/src/components/Timelines/Timeline/Shared/Actions.tsx similarity index 56% rename from src/components/Timelines/Timeline/Shared/ActionsStatus.tsx rename to src/components/Timelines/Timeline/Shared/Actions.tsx index 999086f1..de7ae17d 100644 --- a/src/components/Timelines/Timeline/Shared/ActionsStatus.tsx +++ b/src/components/Timelines/Timeline/Shared/Actions.tsx @@ -1,16 +1,12 @@ -import React, { useCallback, useMemo, useState } from 'react' +import React, { useCallback, useMemo } from 'react' import { ActionSheetIOS, Pressable, StyleSheet, Text, View } from 'react-native' import { useMutation, useQueryCache } from 'react-query' import { Feather } from '@expo/vector-icons' import client from 'src/api/client' -import { getLocalAccountId } from 'src/utils/slices/instancesSlice' import { useTheme } from 'src/utils/styles/ThemeManager' import { toast } from 'src/components/toast' -import { useSelector } from 'react-redux' import { StyleConstants } from 'src/utils/styles/constants' -import BottomSheet from 'src/components/BottomSheet' -import BottomSheetRow from 'src/components/BottomSheet/Row' const fireMutation = async ({ id, @@ -19,14 +15,8 @@ const fireMutation = async ({ prevState }: { id: string - type: 'favourite' | 'reblog' | 'bookmark' | 'mute' | 'pin' | 'delete' - stateKey: - | 'favourited' - | 'reblogged' - | 'bookmarked' - | 'muted' - | 'pinned' - | 'id' + type: 'favourite' | 'reblog' | 'bookmark' + stateKey: 'favourited' | 'reblogged' | 'bookmarked' prevState?: boolean }) => { let res @@ -34,8 +24,6 @@ const fireMutation = async ({ case 'favourite': case 'reblog': case 'bookmark': - case 'mute': - case 'pin': res = await client({ method: 'post', instance: 'local', @@ -50,21 +38,6 @@ const fireMutation = async ({ return Promise.reject() } break - case 'delete': - res = await client({ - method: 'delete', - instance: 'local', - endpoint: `statuses/${id}` - }) - - if (res.body[stateKey] === id) { - toast({ type: 'success', content: '删除成功' }) - return Promise.resolve(res.body) - } else { - toast({ type: 'error', content: '删除失败' }) - return Promise.reject() - } - break } } @@ -73,15 +46,12 @@ export interface Props { status: Mastodon.Status } -const ActionsStatus: React.FC = ({ queryKey, status }) => { +const TimelineActions: React.FC = ({ queryKey, status }) => { const { theme } = useTheme() const iconColor = theme.secondary const iconColorAction = (state: boolean) => state ? theme.primary : theme.secondary - const localAccountId = useSelector(getLocalAccountId) - const [bottomSheetVisible, setBottomSheetVisible] = useState(false) - const queryCache = useQueryCache() const [mutateAction] = useMutation(fireMutation, { onMutate: ({ id, type, stateKey, prevState }) => { @@ -92,8 +62,6 @@ const ActionsStatus: React.FC = ({ queryKey, status }) => { case 'favourite': case 'reblog': case 'bookmark': - case 'mute': - case 'pin': queryCache.setQueryData(queryKey, old => (old as {}[]).map((paging: any) => ({ toots: paging.toots.map((toot: any) => { @@ -107,19 +75,6 @@ const ActionsStatus: React.FC = ({ queryKey, status }) => { })) ) break - case 'delete': - queryCache.setQueryData(queryKey, old => - (old as {}[]).map((paging: any) => ({ - toots: paging.toots.map((toot: any, index: number) => { - if (toot.id === id) { - paging.toots.splice(index, 1) - } - return toot - }), - pointer: paging.pointer - })) - ) - break } return oldData @@ -161,7 +116,23 @@ const ActionsStatus: React.FC = ({ queryKey, status }) => { }), [status.bookmarked] ) - const onPressShare = useCallback(() => setBottomSheetVisible(true), []) + const onPressShare = useCallback( + () => + ActionSheetIOS.showShareActionSheetWithOptions( + { + url: status.uri, + excludedActivityTypes: [ + 'com.apple.UIKit.activity.Mail', + 'com.apple.UIKit.activity.Print', + 'com.apple.UIKit.activity.SaveToCameraRoll', + 'com.apple.UIKit.activity.OpenInIBooks' + ] + }, + () => {}, + () => {} + ), + [] + ) const childrenReply = useMemo( () => ( @@ -268,86 +239,6 @@ const ActionsStatus: React.FC = ({ queryKey, status }) => { children={childrenShare} /> - - setBottomSheetVisible(false)} - > - { - ActionSheetIOS.showShareActionSheetWithOptions( - { - url: status.uri, - 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: '分享成功' }) - } - ) - }} - icon='share' - text={'分享嘟嘟'} - /> - {status.account.id === localAccountId && ( - { - setBottomSheetVisible(false) - mutateAction({ - id: status.id, - type: 'delete', - stateKey: 'id' - }) - }} - icon='trash' - text='删除嘟嘟' - /> - )} - {status.account.id === localAccountId && ( - { - console.warn('功能未开发') - }} - icon='trash' - text='删除并重发' - /> - )} - { - setBottomSheetVisible(false) - mutateAction({ - id: status.id, - type: 'mute', - stateKey: 'muted', - prevState: status.muted - }) - }} - icon='volume-x' - text={status.muted ? '取消静音' : '静音'} - /> - {/* Also note that reblogs cannot be pinned. */} - {status.account.id === localAccountId && ( - { - setBottomSheetVisible(false) - mutateAction({ - id: status.id, - type: 'pin', - stateKey: 'pinned', - prevState: status.pinned - }) - }} - icon='anchor' - text={status.pinned ? '取消置顶' : '置顶'} - /> - )} - ) } @@ -363,22 +254,7 @@ const styles = StyleSheet.create({ width: '20%', flexDirection: 'row', justifyContent: 'center' - }, - modalBackground: { - width: '100%', - height: '100%', - backgroundColor: 'rgba(0, 0, 0, 0.75)', - flex: 1, - flexDirection: 'row', - justifyContent: 'center', - alignItems: 'flex-end' - }, - modalSheet: { - width: '100%', - height: '50%', - backgroundColor: 'white', - flex: 1 } }) -export default ActionsStatus +export default TimelineActions diff --git a/src/components/Timelines/Timeline/Shared/Attachment.tsx b/src/components/Timelines/Timeline/Shared/Attachment.tsx index be6c24cd..d7812325 100644 --- a/src/components/Timelines/Timeline/Shared/Attachment.tsx +++ b/src/components/Timelines/Timeline/Shared/Attachment.tsx @@ -1,65 +1,58 @@ -import React from 'react' -import { Text, View } from 'react-native' +import { BlurView } from 'expo-blur' +import React, { useCallback, useEffect, useState } from 'react' +import { Pressable, StyleSheet, Text, View } from 'react-native' +import { StyleConstants } from 'src/utils/styles/constants' +import { useTheme } from 'src/utils/styles/ThemeManager' import AttachmentImage from './Attachment/AttachmentImage' import AttachmentVideo from './Attachment/AttachmentVideo' export interface Props { - media_attachments: Mastodon.Attachment[] - sensitive: boolean + status: Pick width: number } -const Attachment: React.FC = ({ - media_attachments, - sensitive, - width -}) => { +const TimelineAttachment: React.FC = ({ status, width }) => { + const { mode, theme } = useTheme() + const allTypes = status.media_attachments.map(m => m.type) let attachment let attachmentHeight - // if (width) {} - switch (media_attachments[0].type) { - case 'unknown': - attachment = 文件不支持 - attachmentHeight = 25 - break - case 'image': - attachment = ( - - ) - attachmentHeight = width / 2 - break - case 'gifv': - attachment = ( - - ) - attachmentHeight = - (width / media_attachments[0].meta.original.width) * - media_attachments[0].meta.original.height - break - // Support multiple video - // Supoort when video meta is empty - // case 'video': - // attachment = ( - // - // ) - // attachmentHeight = - // (width / media_attachments[0].meta.original.width) * - // media_attachments[0].meta.original.height - // break - // case 'audio': + + if (allTypes.includes('image')) { + attachment = ( + + ) + attachmentHeight = (width / 16) * 9 + } else if (allTypes.includes('gifv')) { + attachment = ( + + ) + attachmentHeight = + status.media_attachments[0].meta?.original?.width && + status.media_attachments[0].meta?.original?.height + ? (width / status.media_attachments[0].meta.original.width) * + status.media_attachments[0].meta.original.height + : (width / 16) * 9 + } else if (allTypes.includes('video')) { + attachment = ( + + ) + attachmentHeight = + status.media_attachments[0].meta?.original?.width && + status.media_attachments[0].meta?.original?.height + ? (width / status.media_attachments[0].meta.original.width) * + status.media_attachments[0].meta.original.height + : (width / 16) * 9 + } else if (allTypes.includes('audio')) { // attachment = ( // = ({ // width={width} // /> // ) - // break + } else { + attachment = 文件不支持 + attachmentHeight = 25 } + const [sensitiveShown, setSensitiveShown] = useState(true) + const onPressBlurView = useCallback(() => { + setSensitiveShown(false) + }, []) + useEffect(() => { + if (status.sensitive && sensitiveShown === false) { + setTimeout(() => { + setSensitiveShown(true) + }, 10000) + } + }, [sensitiveShown]) + return ( {attachment} + {status.sensitive && sensitiveShown && ( + + + + 显示敏感内容 + + + + )} ) } -export default React.memo(Attachment, () => true) +const styles = StyleSheet.create({ + blurView: { + position: 'absolute', + width: '100%', + height: '100%' + }, + blurViewPressable: { + flex: 1, + justifyContent: 'center', + alignItems: 'center' + }, + sensitiveText: { + fontSize: StyleConstants.Font.Size.M + } +}) + +export default React.memo(TimelineAttachment, () => true) diff --git a/src/components/Timelines/Timeline/Shared/Attachment/AttachmentImage.tsx b/src/components/Timelines/Timeline/Shared/Attachment/AttachmentImage.tsx index ce8437b6..8d9709e3 100644 --- a/src/components/Timelines/Timeline/Shared/Attachment/AttachmentImage.tsx +++ b/src/components/Timelines/Timeline/Shared/Attachment/AttachmentImage.tsx @@ -1,75 +1,46 @@ -import React, { useEffect, useState } from 'react' -import { Button, Image, Modal, StyleSheet, Pressable, View } from 'react-native' +import React, { useState } from 'react' +import { Image, Modal, StyleSheet, Pressable, View } from 'react-native' import ImageViewer from 'react-native-image-zoom-viewer' +import { StyleConstants } from 'src/utils/styles/constants' export interface Props { media_attachments: Mastodon.Attachment[] - sensitive: boolean width: number } -const AttachmentImage: React.FC = ({ - media_attachments, - sensitive, - width -}) => { - const [mediaSensitive, setMediaSensitive] = useState(sensitive) +const AttachmentImage: React.FC = ({ media_attachments }) => { const [imageModalVisible, setImageModalVisible] = useState(false) const [imageModalIndex, setImageModalIndex] = useState(0) - useEffect(() => { - if (sensitive && mediaSensitive === false) { - setTimeout(() => { - setMediaSensitive(true) - }, 10000) - } - }, [mediaSensitive]) - let images: { url: string; width: number; height: number }[] = [] + let images: { + url: string + width: number | undefined + height: number | undefined + }[] = [] const imagesNode = media_attachments.map((m, i) => { images.push({ url: m.url, - width: m.meta.original.width, - height: m.meta.original.height + width: m.meta?.original?.width || undefined, + height: m.meta?.original?.height || undefined }) return ( { setImageModalIndex(i) setImageModalVisible(true) }} > - + ) }) return ( <> - - {imagesNode} - {mediaSensitive && ( - -