mirror of
				https://github.com/tooot-app/app
				synced 2025-06-05 22:19:13 +02:00 
			
		
		
		
	Basic mentions, hashtags and links highlighting working
This commit is contained in:
		| @@ -12,7 +12,7 @@ import { StatusBar } from 'expo-status-bar' | ||||
|  | ||||
| import Local from 'src/stacks/Local' | ||||
| import Public from 'src/stacks/Public' | ||||
| import Post from 'src/stacks/Post' | ||||
| import PostRoot from 'src/stacks/PostRoot' | ||||
| import Notifications from 'src/stacks/Notifications' | ||||
| import Me from 'src/stacks/Me' | ||||
|  | ||||
| @@ -36,7 +36,7 @@ export const Index: React.FC = () => { | ||||
|                 case 'Public': | ||||
|                   name = 'globe' | ||||
|                   break | ||||
|                 case 'Post': | ||||
|                 case 'PostRoot': | ||||
|                   name = 'plus' | ||||
|                   break | ||||
|                 case 'Notifications': | ||||
| @@ -60,7 +60,22 @@ export const Index: React.FC = () => { | ||||
|         > | ||||
|           <Tab.Screen name='Local' component={Local} /> | ||||
|           <Tab.Screen name='Public' component={Public} /> | ||||
|           <Tab.Screen name='Post' component={Post} /> | ||||
|           <Tab.Screen | ||||
|             name='PostRoot' | ||||
|             component={PostRoot} | ||||
|             listeners={({ navigation, route }) => ({ | ||||
|               tabPress: e => { | ||||
|                 e.preventDefault() | ||||
|                 const { | ||||
|                   length, | ||||
|                   [length - 1]: last | ||||
|                 } = navigation.dangerouslyGetState().history | ||||
|                 navigation.navigate(last.key.split(new RegExp(/(.*?)-/))[1], { | ||||
|                   screen: 'PostToot' | ||||
|                 }) | ||||
|               } | ||||
|             })} | ||||
|           /> | ||||
|           <Tab.Screen name='Notifications' component={Notifications} /> | ||||
|           <Tab.Screen name='Me' component={Me} /> | ||||
|         </Tab.Navigator> | ||||
|   | ||||
| @@ -2,12 +2,14 @@ import store, { RootState } from 'src/stacks/common/store' | ||||
| import ky from 'ky' | ||||
|  | ||||
| const client = async ({ | ||||
|   version = 'v1', | ||||
|   method, | ||||
|   instance, | ||||
|   endpoint, | ||||
|   query, | ||||
|   body | ||||
| }: { | ||||
|   version: 'v1' | 'v2' | ||||
|   method: 'get' | 'post' | 'delete' | ||||
|   instance: 'local' | 'remote' | ||||
|   endpoint: string | ||||
| @@ -16,13 +18,13 @@ const client = async ({ | ||||
|   } | ||||
|   body?: object | ||||
| }): Promise<any> => { | ||||
|   const state: RootState["instanceInfo"] = store.getState().instanceInfo | ||||
|   const state: RootState['instanceInfo'] = store.getState().instanceInfo | ||||
|  | ||||
|   let response | ||||
|   try { | ||||
|     response = await ky(endpoint, { | ||||
|       method: method, | ||||
|       prefixUrl: `https://${state[instance]}/api/v1`, | ||||
|       prefixUrl: `https://${state[instance]}/api/${version}`, | ||||
|       searchParams: query, | ||||
|       headers: { | ||||
|         'Content-Type': 'application/json', | ||||
|   | ||||
| @@ -4,6 +4,8 @@ import { createNativeStackNavigator } from 'react-native-screens/native-stack' | ||||
| import Base from './Me/Base' | ||||
| import Authentication from 'src/stacks/Me/Authentication' | ||||
|  | ||||
| import sharedScreens from 'src/stacks/Shared/sharedScreens' | ||||
|  | ||||
| const Stack = createNativeStackNavigator() | ||||
|  | ||||
| const Me: React.FC = () => { | ||||
| @@ -17,6 +19,8 @@ const Me: React.FC = () => { | ||||
|           stackPresentation: 'modal' | ||||
|         }} | ||||
|       /> | ||||
|  | ||||
|       {sharedScreens(Stack)} | ||||
|     </Stack.Navigator> | ||||
|   ) | ||||
| } | ||||
|   | ||||
| @@ -1,23 +0,0 @@ | ||||
| import React from 'react' | ||||
| import { View } from 'react-native' | ||||
| import { createNativeStackNavigator } from 'react-native-screens/native-stack' | ||||
|  | ||||
| const Stack = createNativeStackNavigator() | ||||
|  | ||||
| const Post: React.FC = () => { | ||||
|   return ( | ||||
|     // <Stack.Navigator> | ||||
|     //   <Stack.Screen name='Me-Base' component={Base} /> | ||||
|     //   <Stack.Screen | ||||
|     //     name='Me-Authentication' | ||||
|     //     component={Authentication} | ||||
|     //     options={{ | ||||
|     //       stackPresentation: 'modal' | ||||
|     //     }} | ||||
|     //   /> | ||||
|     // </Stack.Navigator> | ||||
|     <View></View> | ||||
|   ) | ||||
| } | ||||
|  | ||||
| export default Post | ||||
							
								
								
									
										7
									
								
								src/stacks/PostRoot.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/stacks/PostRoot.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| import React from 'react' | ||||
|  | ||||
| const PostRoot: React.FC = () => { | ||||
|   return <></> | ||||
| } | ||||
|  | ||||
| export default PostRoot | ||||
							
								
								
									
										128
									
								
								src/stacks/Shared/PostToot.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										128
									
								
								src/stacks/Shared/PostToot.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,128 @@ | ||||
| import { Feather } from '@expo/vector-icons' | ||||
| import React, { useCallback, useEffect, useState } from 'react' | ||||
| import { | ||||
|   Keyboard, | ||||
|   Pressable, | ||||
|   StyleSheet, | ||||
|   Text, | ||||
|   TextInput, | ||||
|   View | ||||
| } from 'react-native' | ||||
| import { createNativeStackNavigator } from 'react-native-screens/native-stack' | ||||
| import Autolinker, { HtmlTag } from 'autolinker' | ||||
|  | ||||
| const Stack = createNativeStackNavigator() | ||||
|  | ||||
| const PostTootMain = () => { | ||||
|   const [viewHeight, setViewHeight] = useState(0) | ||||
|   const [keyboardHeight, setKeyboardHeight] = useState(0) | ||||
|   useEffect(() => { | ||||
|     Keyboard.addListener('keyboardDidShow', _keyboardDidShow) | ||||
|     Keyboard.addListener('keyboardDidHide', _keyboardDidHide) | ||||
|  | ||||
|     // cleanup function | ||||
|     return () => { | ||||
|       Keyboard.removeListener('keyboardDidShow', _keyboardDidShow) | ||||
|       Keyboard.removeListener('keyboardDidHide', _keyboardDidHide) | ||||
|     } | ||||
|   }) | ||||
|   const _keyboardDidShow = (props: any) => { | ||||
|     setKeyboardHeight(props.endCoordinates.height) | ||||
|   } | ||||
|  | ||||
|   const _keyboardDidHide = () => { | ||||
|     setKeyboardHeight(0) | ||||
|   } | ||||
|  | ||||
|   const [charCount, setCharCount] = useState(0) | ||||
|   const [formattedText, setFormattedText] = useState<React.ReactNode>() | ||||
|   const onChangeText = useCallback(content => { | ||||
|     const tags: string[] = [] | ||||
|     Autolinker.link(content, { | ||||
|       email: false, | ||||
|       phone: false, | ||||
|       mention: 'twitter', | ||||
|       hashtag: 'twitter', | ||||
|       replaceFn: props => { | ||||
|         const tag = props.getMatchedText() | ||||
|         tags.push(tag) | ||||
|         return tag | ||||
|       } | ||||
|     }) | ||||
|  | ||||
|     let _content = content | ||||
|     const children = [] | ||||
|     tags.forEach(tag => { | ||||
|       const parts = _content.split(tag) | ||||
|       children.push(parts.shift()) | ||||
|       children.push(<Text style={{ color: 'red' }}>{tag}</Text>) | ||||
|       _content = parts.join(tag) | ||||
|     }) | ||||
|     children.push(_content) | ||||
|  | ||||
|     setFormattedText(React.createElement(Text, null, children)) | ||||
|     setCharCount(content.length) | ||||
|   }, []) | ||||
|  | ||||
|   return ( | ||||
|     <View | ||||
|       style={styles.main} | ||||
|       onLayout={({ nativeEvent }) => { | ||||
|         setViewHeight(nativeEvent.layout.height) | ||||
|       }} | ||||
|     > | ||||
|       <TextInput | ||||
|         style={[styles.textInput, { height: viewHeight - keyboardHeight - 44 }]} | ||||
|         autoCapitalize='none' | ||||
|         autoFocus | ||||
|         enablesReturnKeyAutomatically | ||||
|         multiline | ||||
|         placeholder='想说点什么' | ||||
|         // value={rawText} | ||||
|         onChangeText={onChangeText} | ||||
|         scrollEnabled | ||||
|       > | ||||
|         <Text>{formattedText}</Text> | ||||
|       </TextInput> | ||||
|       <Pressable style={styles.additions} onPress={() => Keyboard.dismiss()}> | ||||
|         <Feather name='paperclip' size={24} /> | ||||
|         <Feather name='bar-chart-2' size={24} /> | ||||
|         <Feather name='eye-off' size={24} /> | ||||
|         <Text>{charCount}</Text> | ||||
|       </Pressable> | ||||
|     </View> | ||||
|   ) | ||||
| } | ||||
|  | ||||
| const PostToot: React.FC = () => { | ||||
|   return ( | ||||
|     <Stack.Navigator> | ||||
|       <Stack.Screen | ||||
|         name='PostTootMain' | ||||
|         component={PostTootMain} | ||||
|         options={{ | ||||
|           headerLeft: () => <Text>取消</Text>, | ||||
|           headerCenter: () => <></>, | ||||
|           headerRight: () => <Text>发嘟嘟</Text> | ||||
|         }} | ||||
|       /> | ||||
|     </Stack.Navigator> | ||||
|   ) | ||||
| } | ||||
|  | ||||
| const styles = StyleSheet.create({ | ||||
|   main: { | ||||
|     width: '100%', | ||||
|     height: '100%' | ||||
|   }, | ||||
|   textInput: { | ||||
|     backgroundColor: 'gray' | ||||
|   }, | ||||
|   additions: { | ||||
|     height: 44, | ||||
|     backgroundColor: 'red', | ||||
|     flexDirection: 'row' | ||||
|   } | ||||
| }) | ||||
|  | ||||
| export default PostToot | ||||
| @@ -4,6 +4,7 @@ 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' | ||||
| import PostToot from './PostToot' | ||||
|  | ||||
| const sharedScreens = (Stack: any) => { | ||||
|   return [ | ||||
| @@ -21,7 +22,7 @@ const sharedScreens = (Stack: any) => { | ||||
|       key='Hashtag' | ||||
|       name='Hashtag' | ||||
|       component={Hashtag} | ||||
|       options={({ route }) => ({ | ||||
|       options={({ route }: any) => ({ | ||||
|         title: `#${decodeURIComponent(route.params.hashtag)}` | ||||
|       })} | ||||
|     />, | ||||
| @@ -40,6 +41,14 @@ const sharedScreens = (Stack: any) => { | ||||
|       // options={({ route }) => ({ | ||||
|       //   title: `${route.params.domain}` | ||||
|       // })} | ||||
|     />, | ||||
|     <Stack.Screen | ||||
|       key='PostToot' | ||||
|       name='PostToot' | ||||
|       component={PostToot} | ||||
|       options={{ | ||||
|         stackPresentation: 'modal' | ||||
|       }} | ||||
|     /> | ||||
|   ] | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user