mirror of
https://github.com/tooot-app/app
synced 2025-01-23 07:12:02 +01:00
Basic images working
This commit is contained in:
parent
eefa7e01bd
commit
3f8e451099
13
package-lock.json
generated
13
package-lock.json
generated
@ -6590,6 +6590,19 @@
|
||||
"htmlparser2-without-node-native": "^3.9.2"
|
||||
}
|
||||
},
|
||||
"react-native-image-pan-zoom": {
|
||||
"version": "2.1.12",
|
||||
"resolved": "https://registry.npmjs.org/react-native-image-pan-zoom/-/react-native-image-pan-zoom-2.1.12.tgz",
|
||||
"integrity": "sha512-BF66XeP6dzuANsPmmFsJshM2Jyh/Mo1t8FsGc1L9Q9/sVP8MJULDabB1hms+eAoqgtyhMr5BuXV3E1hJ5U5H6Q=="
|
||||
},
|
||||
"react-native-image-zoom-viewer": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/react-native-image-zoom-viewer/-/react-native-image-zoom-viewer-3.0.1.tgz",
|
||||
"integrity": "sha512-la6s5DNSuq4GCRLsi5CZ29FPjgTpdCuGIRdO5T9rUrAtxrlpBPhhSnHrbmPVxsdtOUvxHacTh2Gfa9+RraMZQA==",
|
||||
"requires": {
|
||||
"react-native-image-pan-zoom": "^2.1.12"
|
||||
}
|
||||
},
|
||||
"react-native-iphone-x-helper": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/react-native-iphone-x-helper/-/react-native-iphone-x-helper-1.3.0.tgz",
|
||||
|
@ -25,6 +25,7 @@
|
||||
"react-native": "https://github.com/expo/react-native/archive/sdk-39.0.3.tar.gz",
|
||||
"react-native-gesture-handler": "~1.7.0",
|
||||
"react-native-htmlview": "^0.16.0",
|
||||
"react-native-image-zoom-viewer": "^3.0.1",
|
||||
"react-native-reanimated": "~1.13.0",
|
||||
"react-native-safe-area-context": "3.1.4",
|
||||
"react-native-screens": "~2.10.1",
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React, { useState } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import React from 'react'
|
||||
import { StyleSheet, View } from 'react-native'
|
||||
|
||||
import Reblog from './TootTimeline/Reblog'
|
||||
@ -11,31 +11,25 @@ import Actions from './TootTimeline/Actions'
|
||||
// Maybe break away notification types? https://docs.joinmastodon.org/entities/notification/
|
||||
|
||||
export default function TootTimeline ({ item, notification }) {
|
||||
const [viewWidth, setViewWidth] = useState()
|
||||
|
||||
let contentAggregated = {}
|
||||
let actualContent
|
||||
if (notification && item.status) {
|
||||
contentAggregated = {
|
||||
content: item.status.content,
|
||||
emojis: item.status.emojis,
|
||||
media_attachments: item.status.media_attachments,
|
||||
mentions: item.status.mentions,
|
||||
tags: item.status.tags
|
||||
}
|
||||
actualContent = item.status
|
||||
} else if (item.reblog) {
|
||||
contentAggregated = {
|
||||
content: item.reblog.content,
|
||||
emojis: item.reblog.emojis,
|
||||
media_attachments: item.reblog.media_attachments,
|
||||
mentions: item.reblog.mentions,
|
||||
tags: item.reblog.tags
|
||||
}
|
||||
actualContent = item.reblog
|
||||
} else {
|
||||
contentAggregated = {
|
||||
content: item.content,
|
||||
emojis: item.emojis,
|
||||
media_attachments: item.media_attachments,
|
||||
mentions: item.mentions,
|
||||
tags: item.tags
|
||||
}
|
||||
actualContent = item
|
||||
}
|
||||
contentAggregated = {
|
||||
content: actualContent.content,
|
||||
emojis: actualContent.emojis,
|
||||
media_attachments: actualContent.media_attachments,
|
||||
mentions: actualContent.mentions,
|
||||
sensitive: actualContent.sensitive,
|
||||
spoiler_text: actualContent.spoiler_text,
|
||||
tags: actualContent.tags
|
||||
}
|
||||
|
||||
return (
|
||||
@ -48,7 +42,10 @@ export default function TootTimeline ({ item, notification }) {
|
||||
)}
|
||||
<View style={styles.toot}>
|
||||
<Avatar uri={item.reblog?.account.avatar || item.account.avatar} />
|
||||
<View style={styles.details}>
|
||||
<View
|
||||
style={styles.details}
|
||||
onLayout={e => setViewWidth(e.nativeEvent.layout.width)}
|
||||
>
|
||||
<Header
|
||||
name={
|
||||
(item.reblog?.account.display_name
|
||||
@ -63,7 +60,7 @@ export default function TootTimeline ({ item, notification }) {
|
||||
created_at={item.created_at}
|
||||
application={item.application || null}
|
||||
/>
|
||||
<Content {...contentAggregated} />
|
||||
<Content {...contentAggregated} width={viewWidth} />
|
||||
</View>
|
||||
</View>
|
||||
<Actions />
|
||||
@ -82,7 +79,8 @@ const styles = StyleSheet.create({
|
||||
flexDirection: 'row'
|
||||
},
|
||||
details: {
|
||||
flex: 1
|
||||
flex: 1,
|
||||
flexGrow: 1
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -1,8 +1,17 @@
|
||||
import React from 'react'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { StyleSheet, Text } from 'react-native'
|
||||
import { useNavigation } from '@react-navigation/native'
|
||||
import {
|
||||
Button,
|
||||
Image,
|
||||
Modal,
|
||||
StyleSheet,
|
||||
Text,
|
||||
TouchableHighlight,
|
||||
View
|
||||
} from 'react-native'
|
||||
import HTMLView from 'react-native-htmlview'
|
||||
import ImageViewer from 'react-native-image-zoom-viewer'
|
||||
import { useNavigation } from '@react-navigation/native'
|
||||
|
||||
import Emojis from './Emojis'
|
||||
|
||||
@ -67,31 +76,154 @@ function renderNode (navigation, node, index, mentions) {
|
||||
}
|
||||
}
|
||||
|
||||
function Media ({ media_attachments, sensitive, width }) {
|
||||
const [mediaSensitive, setMediaSensitive] = useState(sensitive)
|
||||
const [imageModalVisible, setImageModalVisible] = useState(false)
|
||||
const [imageModalIndex, setImageModalIndex] = useState(0)
|
||||
useEffect(() => {
|
||||
if (sensitive && mediaSensitive === false) {
|
||||
setTimeout(() => {
|
||||
setMediaSensitive(true)
|
||||
}, 10000)
|
||||
}
|
||||
}, [mediaSensitive])
|
||||
|
||||
let images = []
|
||||
if (width) {
|
||||
const calWidth = i => {
|
||||
if (media_attachments.length === 1) {
|
||||
return { flexGrow: 1, aspectRatio: 16 / 9 }
|
||||
} else if (media_attachments.length === 3 && i === 2) {
|
||||
return { flexGrow: 1, aspectRatio: 16 / 9 }
|
||||
} else {
|
||||
return { flexBasis: width / 2 - 4, aspectRatio: 16 / 9 }
|
||||
}
|
||||
}
|
||||
|
||||
media_attachments = media_attachments.map((m, i) => {
|
||||
switch (m.type) {
|
||||
case 'unknown':
|
||||
return <Text key={i}>文件不支持</Text>
|
||||
case 'image':
|
||||
images.push({
|
||||
url: m.url,
|
||||
width: m.meta.original.width,
|
||||
height: m.meta.original.height
|
||||
})
|
||||
return (
|
||||
<TouchableHighlight
|
||||
key={i}
|
||||
style={calWidth(i)}
|
||||
onPress={() => {
|
||||
setImageModalIndex(i)
|
||||
setImageModalVisible(true)
|
||||
}}
|
||||
>
|
||||
<Image
|
||||
source={{ uri: m.preview_url }}
|
||||
style={styles.image}
|
||||
blurRadius={mediaSensitive ? 50 : 0}
|
||||
/>
|
||||
</TouchableHighlight>
|
||||
)
|
||||
}
|
||||
})
|
||||
if (images) {
|
||||
return (
|
||||
<>
|
||||
<View style={styles.media}>
|
||||
{media_attachments}
|
||||
{mediaSensitive && (
|
||||
<View
|
||||
style={{
|
||||
position: 'absolute',
|
||||
width: '100%',
|
||||
height: '100%'
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
title='Press me'
|
||||
onPress={() => {
|
||||
setMediaSensitive(false)
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
<Modal
|
||||
visible={imageModalVisible}
|
||||
transparent={true}
|
||||
animationType='fade'
|
||||
>
|
||||
<ImageViewer
|
||||
imageUrls={images}
|
||||
index={imageModalIndex}
|
||||
onSwipeDown={() => setImageModalVisible(false)}
|
||||
enableSwipeDown={true}
|
||||
swipeDownThreshold={100}
|
||||
useNativeDriver={true}
|
||||
/>
|
||||
</Modal>
|
||||
</>
|
||||
)
|
||||
} else {
|
||||
return <View style={styles.media}>{media_attachments}</View>
|
||||
}
|
||||
} else {
|
||||
return <></>
|
||||
}
|
||||
}
|
||||
|
||||
export default function Content ({
|
||||
content,
|
||||
emojis,
|
||||
media_attachments,
|
||||
mentions,
|
||||
tags
|
||||
sensitive,
|
||||
spoiler_text,
|
||||
tags,
|
||||
width
|
||||
}) {
|
||||
const navigation = useNavigation()
|
||||
|
||||
return content ? (
|
||||
<HTMLView
|
||||
value={content}
|
||||
renderNode={(node, index) =>
|
||||
renderNode(navigation, node, index, mentions)
|
||||
}
|
||||
TextComponent={({ children }) => (
|
||||
<Emojis content={children} emojis={emojis} dimension={14} />
|
||||
)}
|
||||
/>
|
||||
) : (
|
||||
<></>
|
||||
)
|
||||
let fullContent = []
|
||||
if (content) {
|
||||
fullContent.push(
|
||||
<HTMLView
|
||||
key='content'
|
||||
value={content}
|
||||
renderNode={(node, index) =>
|
||||
renderNode(navigation, node, index, mentions)
|
||||
}
|
||||
TextComponent={({ children }) => (
|
||||
<Emojis content={children} emojis={emojis} dimension={14} />
|
||||
)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
if (media_attachments) {
|
||||
fullContent.push(
|
||||
<Media
|
||||
key='media'
|
||||
media_attachments={media_attachments}
|
||||
sensitive={sensitive}
|
||||
width={width}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
return fullContent
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
media: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between'
|
||||
},
|
||||
image: {
|
||||
width: '100%',
|
||||
height: '100%'
|
||||
},
|
||||
a: {
|
||||
color: 'blue'
|
||||
}
|
||||
|
@ -29,7 +29,9 @@ export default function Timeline ({ page, hashtag, list }) {
|
||||
<FlatList
|
||||
data={state.toots}
|
||||
keyExtractor={({ id }) => id}
|
||||
renderItem={TootTimeline}
|
||||
renderItem={({ item, index, separators }) => (
|
||||
<TootTimeline key={item.key} item={item} />
|
||||
)}
|
||||
onRefresh={() =>
|
||||
dispatch(fetch({ page, query: { since_id: state.toots[0].id } }))
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user