diff --git a/App.jsx b/App.jsx index 1ec6b0f..5aaab0d 100644 --- a/App.jsx +++ b/App.jsx @@ -1,12 +1,13 @@ import React, { useState, useEffect, + useRef, useReducer, useMemo, createContext, useCallback, } from "react"; -import { View } from "react-native"; +import { View, AppState } from "react-native"; import * as SplashScreen from "expo-splash-screen"; import HomeTab from "./screeens/HomeTab"; import Login from "./screeens/Login"; @@ -35,11 +36,13 @@ import WechatWaitingToAdd from "./screeens/WechatWaitingToAdd"; import Search from "./screeens/Search"; import WebWithHeader from "./screeens/WebWithHeader"; import UpdateModal from "./components/UpdateModal"; +import StreamerNavigatorModal from "./components/StreamerNavigatorModal"; import { Icon } from "@rneui/themed"; import { StatusBar } from "expo-status-bar"; import { save, get, remove, storeAppInfo } from "./utils/storeInfo"; import baseRequest from "./utils/baseRequest"; import { generateSignature } from "./utils/crypto"; +import * as Clipboard from "expo-clipboard"; const RootStack = createNativeStackNavigator(); @@ -57,6 +60,9 @@ export default function App() { }, }; + //保存用户剪贴板内容 + const [inviterCode, setInviterCode] = useState(); + //获取环境变量 const apiUrl = process.env.EXPO_PUBLIC_API_URL; //登录逻辑 @@ -99,8 +105,9 @@ export default function App() { dispatch({ type: "SIGN_OUT" }); } }, + inviterCode: inviterCode, }), - [] + [inviterCode] ); //控制开屏图片出现 const [appIsReady, setAppIsReady] = useState(false); @@ -166,6 +173,92 @@ export default function App() { prepare(); }, []); + //获取用户剪贴板内容 + const getClipboardContent = useCallback(async () => { + const content = await Clipboard.getStringAsync(); + const pattern = /https:\/\/tiefen\.fun\/(\d+)/; + const match = content.match(pattern); + if (match && match[1]) { + const intInviterCode = parseInt(match[1], 10); + setInviterCode(intInviterCode); + await Clipboard.setStringAsync(""); + return; + } + setInviterCode(null); + }, []); + + //当用户未登录时,获取剪贴板内容,用于绑定邀请人 + useEffect(() => { + if (state.isSignin) return; + getClipboardContent(); + }, []); + + //每次从后台切换到前台时,获取用户剪贴板内容 + const appState = useRef(AppState.currentState); + useEffect(() => { + if (!state.isSignin) return; + const subscription = AppState.addEventListener("change", (nextAppState) => { + if ( + appState.current.match(/inactive|background/) && + nextAppState === "active" + ) { + getClipboardContent(); + } + appState.current = nextAppState; + }); + + return () => { + subscription.remove(); + }; + }, [state.isSignin]); + + //当用户已经登录,查看根据剪贴板内容展示主播Modal + const [streamerNavigatorModalStatus, setStreamerNavigatorModalStatus] = + useState({ + open: false, + data: {}, + }); + useEffect(() => { + const getInviterData = async () => { + //获取主播数据 + if (!inviterCode) return; + if (!state.isSignin) return; + if (isUpdateModalVisible) return; + try { + const base = await baseRequest(); + const signature = await generateSignature({ + user_id: inviterCode, + ...base, + }); + const inviterResponse = await fetch( + `${apiUrl}/api/streamer/list_ext_by_user_id?signature=${signature}`, + { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + user_id: inviterCode, + ...base, + }), + } + ); + const inviterData = await inviterResponse.json(); + if (inviterData.ret === -1) { + return; + } + setStreamerNavigatorModalStatus({ + open: true, + data: inviterData.data.streamer_ext, + }); + } catch (e) { + console.warn(e); + } + }; + getInviterData(); + }, [state.isSignin, inviterCode, isUpdateModalVisible]); + + //展示和隐藏splash const onLayoutRootView = useCallback(async () => { if (appIsReady) { await SplashScreen.hideAsync(); @@ -454,6 +547,10 @@ export default function App() { )} + diff --git a/components/StreamerNavigatorModal/index.jsx b/components/StreamerNavigatorModal/index.jsx new file mode 100644 index 0000000..e4041d7 --- /dev/null +++ b/components/StreamerNavigatorModal/index.jsx @@ -0,0 +1,86 @@ +import { + View, + Text, + Modal, + TouchableOpacity, + Image as NativeImage, +} from "react-native"; +import React from "react"; +import { useTailwind } from "tailwind-rn"; +import { Button } from "@rneui/themed"; +import { Image } from "expo-image"; +import { useNavigation } from "@react-navigation/native"; + +export default function StreamerNavigatorModal({ status, setStatus }) { + const tailwind = useTailwind(); + const blurhash = "LcKUTa%gOYWBYRt6xuoJo~s8V@fk"; + const navigation = useNavigation(); + + return ( + + setStatus({ ...status, open: false })} + style={{ + backgroundColor: "#00000080", + ...tailwind("flex-1 justify-center items-center"), + }} + > + + + + + + + {status.data?.name} + + + + + {status.data?.bio} + + + + + + + + ); +} diff --git a/screeens/Login/PhoneNumLogin/index.jsx b/screeens/Login/PhoneNumLogin/index.jsx index 6d3e9f0..3896dd0 100644 --- a/screeens/Login/PhoneNumLogin/index.jsx +++ b/screeens/Login/PhoneNumLogin/index.jsx @@ -12,7 +12,7 @@ import { get, save } from "../../../utils/storeInfo"; import { generateSignature } from "../../../utils/crypto"; export default function PhoneNumLogin() { - const { signIn } = useContext(AuthContext); + const { signIn, inviterCode } = useContext(AuthContext); const navigation = useNavigation(); const tailwind = useTailwind(); //设置checkbox @@ -137,6 +137,7 @@ export default function PhoneNumLogin() { mobile_phone: mobile_phone, region_code: regionCode, veri_code: veriCode, + inviter: inviterCode, ...base, }); try { @@ -151,6 +152,7 @@ export default function PhoneNumLogin() { mobile_phone: mobile_phone, region_code: regionCode, veri_code: veriCode, + inviter: inviterCode, ...base, }), } diff --git a/tailwind.css b/tailwind.css index 779ba3b..7088f4b 100644 --- a/tailwind.css +++ b/tailwind.css @@ -717,14 +717,6 @@ text-align: right } -.text-start { - text-align: start -} - -.text-end { - text-align: end -} - .text-2xl { font-size: 1.5rem; line-height: 2rem diff --git a/tailwind.json b/tailwind.json index 054f3b3..af18246 100644 --- a/tailwind.json +++ b/tailwind.json @@ -955,16 +955,6 @@ "textAlign": "right" } }, - "text-start": { - "style": { - "textAlign": "start" - } - }, - "text-end": { - "style": { - "textAlign": "end" - } - }, "text-2xl": { "style": { "fontSize": 24,