读取剪贴板,注册时绑定主播,登录后显示主播弹窗
This commit is contained in:
parent
1e599f02dc
commit
d518750660
101
App.jsx
101
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() {
|
|||
</>
|
||||
)}
|
||||
</RootStack.Navigator>
|
||||
<StreamerNavigatorModal
|
||||
status={streamerNavigatorModalStatus}
|
||||
setStatus={setStreamerNavigatorModalStatus}
|
||||
/>
|
||||
</NavigationContainer>
|
||||
</View>
|
||||
<Toast />
|
||||
|
|
|
@ -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 (
|
||||
<Modal
|
||||
visible={status.open}
|
||||
transparent={true}
|
||||
statusBarTranslucent
|
||||
animationType="fade"
|
||||
>
|
||||
<TouchableOpacity
|
||||
activeOpacity={1}
|
||||
onPress={() => setStatus({ ...status, open: false })}
|
||||
style={{
|
||||
backgroundColor: "#00000080",
|
||||
...tailwind("flex-1 justify-center items-center"),
|
||||
}}
|
||||
>
|
||||
<TouchableOpacity
|
||||
activeOpacity={1}
|
||||
style={tailwind(
|
||||
"rounded-2xl bg-[#1E1C29] items-center w-3/4 overflow-hidden"
|
||||
)}
|
||||
>
|
||||
<View style={tailwind("flex flex-col w-full")}>
|
||||
<Image
|
||||
source={status.data?.cover?.images[0]?.urls[0]}
|
||||
contentFit="cover"
|
||||
transition={1000}
|
||||
placeholder={blurhash}
|
||||
cachePolicy="disk"
|
||||
style={{ aspectRatio: 1, ...tailwind("w-full") }}
|
||||
/>
|
||||
<View style={tailwind("p-4")}>
|
||||
<View style={tailwind("flex flex-row items-center")}>
|
||||
<Text
|
||||
style={tailwind("text-xl text-white font-medium mr-1")}
|
||||
numberOfLines={1}
|
||||
ellipsizeMode="tail"
|
||||
>
|
||||
{status.data?.name}
|
||||
</Text>
|
||||
<NativeImage
|
||||
source={require("../../assets/icon/others/verification.png")}
|
||||
/>
|
||||
</View>
|
||||
<Text style={tailwind("text-sm text-[#FFFFFFB2] mt-1")}>
|
||||
{status.data?.bio}
|
||||
</Text>
|
||||
<Button
|
||||
onPress={() => {
|
||||
navigation.navigate("StreamerProfile", {
|
||||
mid: status.data?.mid,
|
||||
});
|
||||
setStatus({ ...status, open: false });
|
||||
}}
|
||||
color="#FF669E"
|
||||
radius="999"
|
||||
size="md"
|
||||
titleStyle={tailwind("text-base")}
|
||||
containerStyle={tailwind("w-full px-4 mt-4")}
|
||||
>
|
||||
查看主页
|
||||
</Button>
|
||||
</View>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
</TouchableOpacity>
|
||||
</Modal>
|
||||
);
|
||||
}
|
|
@ -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,
|
||||
}),
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -955,16 +955,6 @@
|
|||
"textAlign": "right"
|
||||
}
|
||||
},
|
||||
"text-start": {
|
||||
"style": {
|
||||
"textAlign": "start"
|
||||
}
|
||||
},
|
||||
"text-end": {
|
||||
"style": {
|
||||
"textAlign": "end"
|
||||
}
|
||||
},
|
||||
"text-2xl": {
|
||||
"style": {
|
||||
"fontSize": 24,
|
||||
|
|
Loading…
Reference in New Issue