mirror of
				https://github.com/tooot-app/app
				synced 2025-06-05 22:19:13 +02:00 
			
		
		
		
	Video working
This commit is contained in:
		| @@ -75,7 +75,8 @@ const styles = StyleSheet.create({ | |||||||
| }) | }) | ||||||
|  |  | ||||||
| Actioned.propTypes = { | Actioned.propTypes = { | ||||||
|   action: PropTypes.oneOf(['favourite', 'follow', 'poll', 'reblog']).isRequired, |   action: PropTypes.oneOf(['favourite', 'follow', 'mention', 'poll', 'reblog']) | ||||||
|  |     .isRequired, | ||||||
|   name: PropTypes.string, |   name: PropTypes.string, | ||||||
|   emojis: PropTypes.arrayOf(propTypesEmoji), |   emojis: PropTypes.arrayOf(propTypesEmoji), | ||||||
|   notification: PropTypes.bool |   notification: PropTypes.bool | ||||||
|   | |||||||
							
								
								
									
										81
									
								
								src/components/Toot/Attachment.jsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								src/components/Toot/Attachment.jsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,81 @@ | |||||||
|  | import React from 'react' | ||||||
|  | import PropTypes from 'prop-types' | ||||||
|  | import propTypesAttachment from 'src/prop-types/attachment' | ||||||
|  | import { Text, View } from 'react-native' | ||||||
|  |  | ||||||
|  | import AttachmentImage from './Attachment/AttachmentImage' | ||||||
|  | import AttachmentVideo from './Attachment/AttachmentVideo' | ||||||
|  |  | ||||||
|  | export default function Attachment ({ media_attachments, sensitive, width }) { | ||||||
|  |   let attachment | ||||||
|  |   let attachmentHeight | ||||||
|  |   // if (width) {} | ||||||
|  |   switch (media_attachments[0].type) { | ||||||
|  |     case 'unknown': | ||||||
|  |       attachment = <Text>文件不支持</Text> | ||||||
|  |       attachmentHeight = 25 | ||||||
|  |       break | ||||||
|  |     case 'image': | ||||||
|  |       attachment = ( | ||||||
|  |         <AttachmentImage | ||||||
|  |           media_attachments={media_attachments} | ||||||
|  |           sensitive={sensitive} | ||||||
|  |           width={width} | ||||||
|  |         /> | ||||||
|  |       ) | ||||||
|  |       attachmentHeight = width / 2 | ||||||
|  |       break | ||||||
|  |     case 'gifv': | ||||||
|  |       attachment = ( | ||||||
|  |         <AttachmentVideo | ||||||
|  |           media_attachments={media_attachments} | ||||||
|  |           sensitive={sensitive} | ||||||
|  |           width={width} | ||||||
|  |         /> | ||||||
|  |       ) | ||||||
|  |       attachmentHeight = | ||||||
|  |         (width / media_attachments[0].meta.original.width) * | ||||||
|  |         media_attachments[0].meta.original.height | ||||||
|  |       break | ||||||
|  |     case 'video': | ||||||
|  |       attachment = ( | ||||||
|  |         <AttachmentVideo | ||||||
|  |           media_attachments={media_attachments} | ||||||
|  |           sensitive={sensitive} | ||||||
|  |           width={width} | ||||||
|  |         /> | ||||||
|  |       ) | ||||||
|  |       attachmentHeight = | ||||||
|  |         (width / media_attachments[0].meta.original.width) * | ||||||
|  |         media_attachments[0].meta.original.height | ||||||
|  |       break | ||||||
|  |     // case 'audio': | ||||||
|  |     //   attachment = ( | ||||||
|  |     //     <AttachmentAudio | ||||||
|  |     //       media_attachments={media_attachments} | ||||||
|  |     //       sensitive={sensitive} | ||||||
|  |     //       width={width} | ||||||
|  |     //     /> | ||||||
|  |     //   ) | ||||||
|  |     //   break | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   return ( | ||||||
|  |     <View | ||||||
|  |       style={{ | ||||||
|  |         width: width + 8, | ||||||
|  |         height: attachmentHeight, | ||||||
|  |         marginTop: 4, | ||||||
|  |         marginLeft: -4 | ||||||
|  |       }} | ||||||
|  |     > | ||||||
|  |       {attachment} | ||||||
|  |     </View> | ||||||
|  |   ) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | Attachment.propTypes = { | ||||||
|  |   media_attachments: PropTypes.arrayOf(propTypesAttachment), | ||||||
|  |   sensitive: PropTypes.bool.isRequired, | ||||||
|  |   width: PropTypes.number.isRequired | ||||||
|  | } | ||||||
							
								
								
									
										102
									
								
								src/components/Toot/Attachment/AttachmentImage.jsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								src/components/Toot/Attachment/AttachmentImage.jsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,102 @@ | |||||||
|  | import React, { useEffect, useState } from 'react' | ||||||
|  | import PropTypes from 'prop-types' | ||||||
|  | import propTypesAttachment from 'src/prop-types/attachment' | ||||||
|  | import { Button, Image, Modal, StyleSheet, Pressable, View } from 'react-native' | ||||||
|  | import ImageViewer from 'react-native-image-zoom-viewer' | ||||||
|  |  | ||||||
|  | export default function AttachmentImage ({ 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 = [] | ||||||
|  |   media_attachments = media_attachments.map((m, i) => { | ||||||
|  |     images.push({ | ||||||
|  |       url: m.url, | ||||||
|  |       width: m.meta.original.width, | ||||||
|  |       height: m.meta.original.height | ||||||
|  |     }) | ||||||
|  |     return ( | ||||||
|  |       <Pressable | ||||||
|  |         key={i} | ||||||
|  |         style={{ flexGrow: 1, height: width / 2, margin: 4 }} | ||||||
|  |         onPress={() => { | ||||||
|  |           setImageModalIndex(i) | ||||||
|  |           setImageModalVisible(true) | ||||||
|  |         }} | ||||||
|  |       > | ||||||
|  |         <Image | ||||||
|  |           source={{ uri: m.preview_url }} | ||||||
|  |           style={styles.image} | ||||||
|  |           blurRadius={mediaSensitive ? width / 5 : 0} | ||||||
|  |         /> | ||||||
|  |       </Pressable> | ||||||
|  |     ) | ||||||
|  |   }) | ||||||
|  |  | ||||||
|  |   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> | ||||||
|  |     </> | ||||||
|  |   ) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const styles = StyleSheet.create({ | ||||||
|  |   media: { | ||||||
|  |     flex: 1, | ||||||
|  |     flexDirection: 'column', | ||||||
|  |     flexWrap: 'wrap', | ||||||
|  |     justifyContent: 'space-between', | ||||||
|  |     alignItems: 'stretch', | ||||||
|  |     alignContent: 'stretch' | ||||||
|  |   }, | ||||||
|  |   image: { | ||||||
|  |     width: '100%', | ||||||
|  |     height: '100%' | ||||||
|  |   } | ||||||
|  | }) | ||||||
|  |  | ||||||
|  | AttachmentImage.propTypes = { | ||||||
|  |   media_attachments: PropTypes.arrayOf(propTypesAttachment), | ||||||
|  |   sensitive: PropTypes.bool.isRequired, | ||||||
|  |   width: PropTypes.number.isRequired | ||||||
|  | } | ||||||
							
								
								
									
										72
									
								
								src/components/Toot/Attachment/AttachmentVideo.jsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								src/components/Toot/Attachment/AttachmentVideo.jsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,72 @@ | |||||||
|  | import React, { useRef, useState } from 'react' | ||||||
|  | import PropTypes from 'prop-types' | ||||||
|  | import propTypesAttachment from 'src/prop-types/attachment' | ||||||
|  | import { Pressable, View } from 'react-native' | ||||||
|  | import { Video } from 'expo-av' | ||||||
|  | import { Feather } from '@expo/vector-icons' | ||||||
|  |  | ||||||
|  | export default function AttachmentVideo ({ | ||||||
|  |   media_attachments, | ||||||
|  |   sensitive, | ||||||
|  |   width | ||||||
|  | }) { | ||||||
|  |   const videoPlayer = useRef() | ||||||
|  |   const [mediaSensitive, setMediaSensitive] = useState(sensitive) | ||||||
|  |   const [videoPlay, setVideoPlay] = useState(false) | ||||||
|  |  | ||||||
|  |   const video = media_attachments[0] | ||||||
|  |   const videoWidth = width | ||||||
|  |   const videoHeight = | ||||||
|  |     (width / video.meta.original.width) * video.meta.original.height | ||||||
|  |  | ||||||
|  |   return ( | ||||||
|  |     <View | ||||||
|  |       style={{ | ||||||
|  |         width: videoWidth, | ||||||
|  |         height: videoHeight | ||||||
|  |       }} | ||||||
|  |     > | ||||||
|  |       <Video | ||||||
|  |         ref={videoPlayer} | ||||||
|  |         source={{ uri: video.remote_url }} | ||||||
|  |         style={{ | ||||||
|  |           width: videoWidth, | ||||||
|  |           height: videoHeight | ||||||
|  |         }} | ||||||
|  |         resizeMode='cover' | ||||||
|  |         usePoster | ||||||
|  |         posterSourceThe={{ uri: video.preview_url }} | ||||||
|  |         useNativeControls | ||||||
|  |         shouldPlay={videoPlay} | ||||||
|  |       /> | ||||||
|  |       {!videoPlay && ( | ||||||
|  |         <Pressable | ||||||
|  |           onPress={() => { | ||||||
|  |             setMediaSensitive(false) | ||||||
|  |             videoPlayer.current.presentFullscreenPlayer() | ||||||
|  |             setVideoPlay(true) | ||||||
|  |           }} | ||||||
|  |           style={{ | ||||||
|  |             position: 'absolute', | ||||||
|  |             top: 0, | ||||||
|  |             left: 0, | ||||||
|  |             width: '100%', | ||||||
|  |             height: '100%', | ||||||
|  |             flexDirection: 'row', | ||||||
|  |             alignItems: 'center', | ||||||
|  |             justifyContent: 'center', | ||||||
|  |             backgroundColor: 'rgba(0, 0, 0, 0.25)' | ||||||
|  |           }} | ||||||
|  |         > | ||||||
|  |           <Feather name='play' size={36} color='black' /> | ||||||
|  |         </Pressable> | ||||||
|  |       )} | ||||||
|  |     </View> | ||||||
|  |   ) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | AttachmentVideo.propTypes = { | ||||||
|  |   media_attachments: PropTypes.arrayOf(propTypesAttachment), | ||||||
|  |   sensitive: PropTypes.bool.isRequired, | ||||||
|  |   width: PropTypes.number.isRequired | ||||||
|  | } | ||||||
| @@ -1,138 +0,0 @@ | |||||||
| import React, { useEffect, useState } from 'react' |  | ||||||
| import PropTypes from 'prop-types' |  | ||||||
| import propTypesAttachment from 'src/prop-types/attachment' |  | ||||||
| import { |  | ||||||
|   Button, |  | ||||||
|   Image, |  | ||||||
|   Modal, |  | ||||||
|   StyleSheet, |  | ||||||
|   Text, |  | ||||||
|   Pressable, |  | ||||||
|   View |  | ||||||
| } from 'react-native' |  | ||||||
| import ImageViewer from 'react-native-image-zoom-viewer' |  | ||||||
|  |  | ||||||
| export default 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 media |  | ||||||
|   let images = [] |  | ||||||
|   if (width) { |  | ||||||
|     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 ( |  | ||||||
|             <Pressable |  | ||||||
|               key={i} |  | ||||||
|               style={{ flexGrow: 1, height: width / 2, margin: 4 }} |  | ||||||
|               onPress={() => { |  | ||||||
|                 setImageModalIndex(i) |  | ||||||
|                 setImageModalVisible(true) |  | ||||||
|               }} |  | ||||||
|             > |  | ||||||
|               <Image |  | ||||||
|                 source={{ uri: m.preview_url }} |  | ||||||
|                 style={styles.image} |  | ||||||
|                 blurRadius={mediaSensitive ? width / 5 : 0} |  | ||||||
|               /> |  | ||||||
|             </Pressable> |  | ||||||
|           ) |  | ||||||
|       } |  | ||||||
|     }) |  | ||||||
|     if (images) { |  | ||||||
|       media = ( |  | ||||||
|         <> |  | ||||||
|           <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 { |  | ||||||
|       media = <View style={styles.media}>{media_attachments}</View> |  | ||||||
|     } |  | ||||||
|   } else { |  | ||||||
|     media = <></> |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   return ( |  | ||||||
|     media_attachments.length > 0 && ( |  | ||||||
|       <View |  | ||||||
|         style={{ |  | ||||||
|           width: width + 8, |  | ||||||
|           height: width / 2, |  | ||||||
|           marginTop: 4, |  | ||||||
|           marginLeft: -4 |  | ||||||
|         }} |  | ||||||
|       > |  | ||||||
|         {media} |  | ||||||
|       </View> |  | ||||||
|     ) |  | ||||||
|   ) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| const styles = StyleSheet.create({ |  | ||||||
|   media: { |  | ||||||
|     flex: 1, |  | ||||||
|     flexDirection: 'column', |  | ||||||
|     flexWrap: 'wrap', |  | ||||||
|     justifyContent: 'space-between', |  | ||||||
|     alignItems: 'stretch', |  | ||||||
|     alignContent: 'stretch' |  | ||||||
|   }, |  | ||||||
|   image: { |  | ||||||
|     width: '100%', |  | ||||||
|     height: '100%' |  | ||||||
|   } |  | ||||||
| }) |  | ||||||
|  |  | ||||||
| Media.propTypes = { |  | ||||||
|   media_attachments: PropTypes.arrayOf(propTypesAttachment), |  | ||||||
|   sensitive: PropTypes.bool.isRequired, |  | ||||||
|   width: PropTypes.number.isRequired |  | ||||||
| } |  | ||||||
| @@ -8,7 +8,7 @@ import Avatar from './Toot/Avatar' | |||||||
| import Header from './Toot/Header' | import Header from './Toot/Header' | ||||||
| import Content from './Toot/Content' | import Content from './Toot/Content' | ||||||
| import Poll from './Toot/Poll' | import Poll from './Toot/Poll' | ||||||
| import Media from './Toot/Media' | import Attachment from './Toot/Attachment' | ||||||
| import Card from './Toot/Card' | import Card from './Toot/Card' | ||||||
| import Actions from './Toot/Actions' | import Actions from './Toot/Actions' | ||||||
|  |  | ||||||
| @@ -53,7 +53,7 @@ export default function TootNotification ({ toot }) { | |||||||
|                   )} |                   )} | ||||||
|                   {toot.status.poll && <Poll poll={toot.status.poll} />} |                   {toot.status.poll && <Poll poll={toot.status.poll} />} | ||||||
|                   {toot.status.media_attachments && ( |                   {toot.status.media_attachments && ( | ||||||
|                     <Media |                     <Attachment | ||||||
|                       media_attachments={toot.status.media_attachments} |                       media_attachments={toot.status.media_attachments} | ||||||
|                       sensitive={toot.status.sensitive} |                       sensitive={toot.status.sensitive} | ||||||
|                       width={Dimensions.get('window').width - 24 - 50 - 8} |                       width={Dimensions.get('window').width - 24 - 50 - 8} | ||||||
|   | |||||||
| @@ -8,7 +8,7 @@ import Avatar from './Toot/Avatar' | |||||||
| import Header from './Toot/Header' | import Header from './Toot/Header' | ||||||
| import Content from './Toot/Content' | import Content from './Toot/Content' | ||||||
| import Poll from './Toot/Poll' | import Poll from './Toot/Poll' | ||||||
| import Media from './Toot/Media' | import Attachment from './Toot/Attachment' | ||||||
| import Card from './Toot/Card' | import Card from './Toot/Card' | ||||||
| import Actions from './Toot/Actions' | import Actions from './Toot/Actions' | ||||||
|  |  | ||||||
| @@ -50,9 +50,9 @@ export default function TootTimeline ({ toot }) { | |||||||
|             /> |             /> | ||||||
|             {/* Can pass toot info to next page to speed up performance */} |             {/* Can pass toot info to next page to speed up performance */} | ||||||
|             <Pressable |             <Pressable | ||||||
|               onPress={() => |               // onPress={() => | ||||||
|                 navigation.navigate('Toot', { toot: actualContent.id }) |               //   navigation.navigate('Toot', { toot: actualContent.id }) | ||||||
|               } |               // } | ||||||
|             > |             > | ||||||
|               {actualContent.content ? ( |               {actualContent.content ? ( | ||||||
|                 <Content |                 <Content | ||||||
| @@ -67,8 +67,8 @@ export default function TootTimeline ({ toot }) { | |||||||
|                 <></> |                 <></> | ||||||
|               )} |               )} | ||||||
|               {actualContent.poll && <Poll poll={actualContent.poll} />} |               {actualContent.poll && <Poll poll={actualContent.poll} />} | ||||||
|               {actualContent.media_attachments && ( |               {actualContent.media_attachments.length > 0 && ( | ||||||
|                 <Media |                 <Attachment | ||||||
|                   media_attachments={actualContent.media_attachments} |                   media_attachments={actualContent.media_attachments} | ||||||
|                   sensitive={actualContent.sensitive} |                   sensitive={actualContent.sensitive} | ||||||
|                   width={Dimensions.get('window').width - 24 - 50 - 8} |                   width={Dimensions.get('window').width - 24 - 50 - 8} | ||||||
|   | |||||||
| @@ -3,6 +3,7 @@ import { createNativeStackNavigator } from 'react-native-screens/native-stack' | |||||||
| import { Feather } from '@expo/vector-icons' | import { Feather } from '@expo/vector-icons' | ||||||
|  |  | ||||||
| import Timeline from 'src/stacks/common/Timeline' | import Timeline from 'src/stacks/common/Timeline' | ||||||
|  | import sharedScreens from 'src/stacks/Shared/sharedScreens' | ||||||
|  |  | ||||||
| const Stack = createNativeStackNavigator() | const Stack = createNativeStackNavigator() | ||||||
|  |  | ||||||
| @@ -28,6 +29,8 @@ export default function Notifications () { | |||||||
|       <Stack.Screen name='Notifications'> |       <Stack.Screen name='Notifications'> | ||||||
|         {() => <Timeline page='Notifications' />} |         {() => <Timeline page='Notifications' />} | ||||||
|       </Stack.Screen> |       </Stack.Screen> | ||||||
|  |  | ||||||
|  |       {sharedScreens(Stack)} | ||||||
|     </Stack.Navigator> |     </Stack.Navigator> | ||||||
|   ) |   ) | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										45
									
								
								src/stacks/Shared/sharedScreens.jsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								src/stacks/Shared/sharedScreens.jsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,45 @@ | |||||||
|  | import React from 'react' | ||||||
|  |  | ||||||
|  | import Account from 'src/stacks/Shared/Account' | ||||||
|  | import Hashtag from 'src/stacks/Shared/Hashtag' | ||||||
|  | import Toot from 'src/stacks/Shared/Toot' | ||||||
|  | import Webview from 'src/stacks/Shared/Webview' | ||||||
|  |  | ||||||
|  | export default function sharedScreens (Stack) { | ||||||
|  |   return [ | ||||||
|  |     <Stack.Screen | ||||||
|  |       key='Account' | ||||||
|  |       name='Account' | ||||||
|  |       component={Account} | ||||||
|  |       options={{ | ||||||
|  |         headerTranslucent: true, | ||||||
|  |         headerStyle: { backgroundColor: 'rgba(255, 255, 255, 0)' }, | ||||||
|  |         headerCenter: () => {} | ||||||
|  |       }} | ||||||
|  |     />, | ||||||
|  |     <Stack.Screen | ||||||
|  |       key='Hashtag' | ||||||
|  |       name='Hashtag' | ||||||
|  |       component={Hashtag} | ||||||
|  |       options={({ route }) => ({ | ||||||
|  |         title: `#${decodeURIComponent(route.params.hashtag)}` | ||||||
|  |       })} | ||||||
|  |     />, | ||||||
|  |     <Stack.Screen | ||||||
|  |       key='Toot' | ||||||
|  |       name='Toot' | ||||||
|  |       component={Toot} | ||||||
|  |       options={() => ({ | ||||||
|  |         title: '对话' | ||||||
|  |       })} | ||||||
|  |     />, | ||||||
|  |     <Stack.Screen | ||||||
|  |       key='Webview' | ||||||
|  |       name='Webview' | ||||||
|  |       component={Webview} | ||||||
|  |       // options={({ route }) => ({ | ||||||
|  |       //   title: `${route.params.domain}` | ||||||
|  |       // })} | ||||||
|  |     /> | ||||||
|  |   ] | ||||||
|  | } | ||||||
| @@ -22,10 +22,12 @@ export default function Timeline ({ | |||||||
|   const [timelineReady, setTimelineReady] = useState(false) |   const [timelineReady, setTimelineReady] = useState(false) | ||||||
|  |  | ||||||
|   useEffect(() => { |   useEffect(() => { | ||||||
|     if (state.status === 'idle') { |     let mounted = true | ||||||
|  |     if (state.status === 'idle' && mounted) { | ||||||
|       dispatch(fetch({ page, hashtag, list, toot, account })) |       dispatch(fetch({ page, hashtag, list, toot, account })) | ||||||
|       setTimelineReady(true) |       setTimelineReady(true) | ||||||
|     } |     } | ||||||
|  |     return () => (mounted = false) | ||||||
|   }, [state, dispatch]) |   }, [state, dispatch]) | ||||||
|  |  | ||||||
|   let content |   let content | ||||||
|   | |||||||
| @@ -6,10 +6,7 @@ import SegmentedControl from '@react-native-community/segmented-control' | |||||||
| import { Feather } from '@expo/vector-icons' | import { Feather } from '@expo/vector-icons' | ||||||
|  |  | ||||||
| import Timeline from './Timeline' | import Timeline from './Timeline' | ||||||
| import Account from 'src/stacks/Shared/Account' | import sharedScreens from 'src/stacks/Shared/sharedScreens' | ||||||
| import Hashtag from 'src/stacks/Shared/Hashtag' |  | ||||||
| import Toot from 'src/stacks/Shared/Toot' |  | ||||||
| import Webview from 'src/stacks/Shared/Webview' |  | ||||||
|  |  | ||||||
| const Stack = createNativeStackNavigator() | const Stack = createNativeStackNavigator() | ||||||
|  |  | ||||||
| @@ -93,36 +90,8 @@ export default function TimelinesCombined ({ name, content }) { | |||||||
|           /> |           /> | ||||||
|         )} |         )} | ||||||
|       </Stack.Screen> |       </Stack.Screen> | ||||||
|       <Stack.Screen |  | ||||||
|         name='Account' |       {sharedScreens(Stack)} | ||||||
|         component={Account} |  | ||||||
|         options={{ |  | ||||||
|           headerTranslucent: true, |  | ||||||
|           headerStyle: { backgroundColor: 'rgba(255, 255, 255, 0)' }, |  | ||||||
|           headerCenter: () => {} |  | ||||||
|         }} |  | ||||||
|       /> |  | ||||||
|       <Stack.Screen |  | ||||||
|         name='Hashtag' |  | ||||||
|         component={Hashtag} |  | ||||||
|         options={({ route }) => ({ |  | ||||||
|           title: `#${decodeURIComponent(route.params.hashtag)}` |  | ||||||
|         })} |  | ||||||
|       /> |  | ||||||
|       <Stack.Screen |  | ||||||
|         name='Toot' |  | ||||||
|         component={Toot} |  | ||||||
|         options={() => ({ |  | ||||||
|           title: '对话' |  | ||||||
|         })} |  | ||||||
|       /> |  | ||||||
|       <Stack.Screen |  | ||||||
|         name='Webview' |  | ||||||
|         component={Webview} |  | ||||||
|         // options={({ route }) => ({ |  | ||||||
|         //   title: `${route.params.domain}` |  | ||||||
|         // })} |  | ||||||
|       /> |  | ||||||
|     </Stack.Navigator> |     </Stack.Navigator> | ||||||
|   ) |   ) | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user