Basic images working

This commit is contained in:
Zhiyuan Zheng 2020-10-27 01:51:51 +01:00
parent eefa7e01bd
commit 3f8e451099
No known key found for this signature in database
GPG Key ID: 078A93AB607D85E0
5 changed files with 189 additions and 43 deletions

13
package-lock.json generated
View File

@ -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",

View File

@ -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",

View File

@ -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
}
})

View File

@ -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'
}

View File

@ -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 } }))
}