mirror of
https://github.com/tooot-app/app
synced 2025-02-13 18:30:42 +01:00
Basic mentions, hashtags and links highlighting working
This commit is contained in:
parent
4cbba779c5
commit
97cad12850
@ -17,6 +17,7 @@
|
||||
"@react-navigation/native": "^5.8.6",
|
||||
"@react-navigation/stack": "^5.12.3",
|
||||
"@reduxjs/toolkit": "^1.4.0",
|
||||
"autolinker": "^3.14.2",
|
||||
"expo": "~39.0.4",
|
||||
"expo-app-auth": "~9.2.0",
|
||||
"expo-av": "~8.6.0",
|
||||
@ -58,4 +59,4 @@
|
||||
"typescript": "~3.9.2"
|
||||
},
|
||||
"private": true
|
||||
}
|
||||
}
|
@ -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'
|
||||
}}
|
||||
/>
|
||||
]
|
||||
}
|
||||
|
12
yarn.lock
12
yarn.lock
@ -1670,6 +1670,13 @@ atob@^2.1.2:
|
||||
resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9"
|
||||
integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==
|
||||
|
||||
autolinker@^3.14.2:
|
||||
version "3.14.2"
|
||||
resolved "https://registry.yarnpkg.com/autolinker/-/autolinker-3.14.2.tgz#71856274eb768fb7149039e24d3a2be2f5c55a63"
|
||||
integrity sha512-VO66nXUCZFxTq7fVHAaiAkZNXRQ1l3IFi6D5P7DLoyIEAn2E8g7TWbyEgLlz1uW74LfWmu1A17IPWuPQyGuNVg==
|
||||
dependencies:
|
||||
tslib "^1.9.3"
|
||||
|
||||
available-typed-arrays@^1.0.0, available-typed-arrays@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.2.tgz#6b098ca9d8039079ee3f77f7b783c4480ba513f5"
|
||||
@ -5791,6 +5798,11 @@ toidentifier@1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553"
|
||||
integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==
|
||||
|
||||
tslib@^1.9.3:
|
||||
version "1.14.1"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
|
||||
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
|
||||
|
||||
type-fest@^0.7.1:
|
||||
version "0.7.1"
|
||||
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.7.1.tgz#8dda65feaf03ed78f0a3f9678f1869147f7c5c48"
|
||||
|
Loading…
x
Reference in New Issue
Block a user