From 97cad128503065a21f74b15a868df49622d973e4 Mon Sep 17 00:00:00 2001 From: Zhiyuan Zheng Date: Sun, 8 Nov 2020 01:10:38 +0100 Subject: [PATCH] Basic mentions, hashtags and links highlighting working --- package.json | 3 +- src/Index.tsx | 21 ++++- src/api/client.ts | 6 +- src/stacks/Me.tsx | 4 + src/stacks/Post.tsx | 23 ----- src/stacks/PostRoot.tsx | 7 ++ src/stacks/Shared/PostToot.tsx | 128 ++++++++++++++++++++++++++++ src/stacks/Shared/sharedScreens.tsx | 11 ++- yarn.lock | 12 +++ 9 files changed, 185 insertions(+), 30 deletions(-) delete mode 100644 src/stacks/Post.tsx create mode 100644 src/stacks/PostRoot.tsx create mode 100644 src/stacks/Shared/PostToot.tsx diff --git a/package.json b/package.json index 7db0b0d4..145d2f02 100644 --- a/package.json +++ b/package.json @@ -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 -} +} \ No newline at end of file diff --git a/src/Index.tsx b/src/Index.tsx index 3c238b6d..5cffe4a8 100644 --- a/src/Index.tsx +++ b/src/Index.tsx @@ -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 = () => { > - + ({ + tabPress: e => { + e.preventDefault() + const { + length, + [length - 1]: last + } = navigation.dangerouslyGetState().history + navigation.navigate(last.key.split(new RegExp(/(.*?)-/))[1], { + screen: 'PostToot' + }) + } + })} + /> diff --git a/src/api/client.ts b/src/api/client.ts index 6e745d91..3a00913c 100644 --- a/src/api/client.ts +++ b/src/api/client.ts @@ -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 => { - 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', diff --git a/src/stacks/Me.tsx b/src/stacks/Me.tsx index a954e188..99daf6b4 100644 --- a/src/stacks/Me.tsx +++ b/src/stacks/Me.tsx @@ -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)} ) } diff --git a/src/stacks/Post.tsx b/src/stacks/Post.tsx deleted file mode 100644 index fe026066..00000000 --- a/src/stacks/Post.tsx +++ /dev/null @@ -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 ( - // - // - // - // - - ) -} - -export default Post diff --git a/src/stacks/PostRoot.tsx b/src/stacks/PostRoot.tsx new file mode 100644 index 00000000..a8480732 --- /dev/null +++ b/src/stacks/PostRoot.tsx @@ -0,0 +1,7 @@ +import React from 'react' + +const PostRoot: React.FC = () => { + return <> +} + +export default PostRoot diff --git a/src/stacks/Shared/PostToot.tsx b/src/stacks/Shared/PostToot.tsx new file mode 100644 index 00000000..aeba3f79 --- /dev/null +++ b/src/stacks/Shared/PostToot.tsx @@ -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() + 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({tag}) + _content = parts.join(tag) + }) + children.push(_content) + + setFormattedText(React.createElement(Text, null, children)) + setCharCount(content.length) + }, []) + + return ( + { + setViewHeight(nativeEvent.layout.height) + }} + > + + {formattedText} + + Keyboard.dismiss()}> + + + + {charCount} + + + ) +} + +const PostToot: React.FC = () => { + return ( + + 取消, + headerCenter: () => <>, + headerRight: () => 发嘟嘟 + }} + /> + + ) +} + +const styles = StyleSheet.create({ + main: { + width: '100%', + height: '100%' + }, + textInput: { + backgroundColor: 'gray' + }, + additions: { + height: 44, + backgroundColor: 'red', + flexDirection: 'row' + } +}) + +export default PostToot diff --git a/src/stacks/Shared/sharedScreens.tsx b/src/stacks/Shared/sharedScreens.tsx index 10b8ce97..190c61fc 100644 --- a/src/stacks/Shared/sharedScreens.tsx +++ b/src/stacks/Shared/sharedScreens.tsx @@ -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}` // })} + />, + ] } diff --git a/yarn.lock b/yarn.lock index 755eb329..55a6c294 100644 --- a/yarn.lock +++ b/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"