tiefen_space_app/App.jsx

589 lines
21 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React, {
useState,
useEffect,
useRef,
useReducer,
useMemo,
createContext,
useCallback,
} from "react";
import { View, AppState } from "react-native";
import * as SplashScreen from "expo-splash-screen";
import HomeTab from "./screeens/HomeTab";
import Login from "./screeens/Login";
import StreamerProfile from "./screeens/StreamerProfile";
import UserProfile from "./screeens/UserProfile";
import { createNativeStackNavigator } from "@react-navigation/native-stack";
import { NavigationContainer, DefaultTheme } from "@react-navigation/native";
import { SafeAreaProvider } from "react-native-safe-area-context";
import { TailwindProvider } from "tailwind-rn";
import utilities from "./tailwind.json";
import ForgetPassword from "./screeens/Login/ForgetPassword";
import SetPassword from "./screeens/Login/SetPassword";
import Toast from "react-native-toast-message";
import loginReducer from "./utils/loginReducer";
import MessageDetail from "./screeens/Messages/MessageDetail";
import EditUserProfile from "./screeens/EditUserProfile";
import Wallet from "./screeens/Wallet";
import UnlockedWechat from "./screeens/UnlockedWechat";
import EditStreamerProfile from "./screeens/EditStreamerProfile";
import Relationship from "./screeens/Relationship";
import StreamerVerification from "./screeens/StreamerVerification";
import EditPlatformOrder from "./screeens/EditPlatformOrder";
import StreamerInviteUser from "./screeens/StreamerInviteUser";
import Setting from "./screeens/Setting";
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 } from "./utils/storeInfo";
import baseRequest from "./utils/baseRequest";
import { generateSignature } from "./utils/crypto";
import * as Clipboard from "expo-clipboard";
import PrivatyModal from "./components/PrivatyModal";
const RootStack = createNativeStackNavigator();
export const AuthContext = createContext("");
SplashScreen.preventAutoHideAsync();
export default function App() {
//app主题
const MyTheme = {
...DefaultTheme,
colors: {
...DefaultTheme.colors,
background: "#07050A",
},
};
//保存用户剪贴板内容
const [inviterCode, setInviterCode] = useState();
//未同意用户协议和隐私政策时展示隐私弹窗
const [isPrivatyModalOpen, setIsPrivatyModalOpen] = useState(false);
//隐私弹窗是否同意
const [checked, setChecked] = useState(false);
//如果是第一次打开app则展示隐私弹窗
useEffect(() => {
const handlePrivatyModal = async () => {
const notFirstTimeOpenApp = await get("not_first_time_open_app");
if (!notFirstTimeOpenApp) {
setIsPrivatyModalOpen(true);
save("not_first_time_open_app", 1);
return;
}
};
handlePrivatyModal();
}, []);
//获取环境变量
const apiUrl = process.env.EXPO_PUBLIC_API_URL;
//登录逻辑
const [state, dispatch] = useReducer(loginReducer, {
isSignin: false,
userToken: null,
});
const authContext = useMemo(
() => ({
signIn: async (data, mobilePhone, regionCode) => {
await save("token", data.data.token);
await save("account", data.data.account);
await save("mobile_phone", mobilePhone);
await save("region_code", regionCode);
dispatch({ type: "SIGN_IN", token: data.data.token });
},
signOut: async () => {
const base = await baseRequest();
const account = await get("account");
const signature = await generateSignature({
mid: account?.mid,
...base,
});
try {
await fetch(`${apiUrl}/api/login/logout?signature=${signature}`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
mid: account?.mid,
...base,
}),
});
await remove("token");
await remove("account");
} catch (error) {
console.error(error);
} finally {
dispatch({ type: "SIGN_OUT" });
}
},
inviterCode: inviterCode,
checked: checked,
setChecked: setChecked,
}),
[inviterCode, checked]
);
//控制开屏图片出现
const [appIsReady, setAppIsReady] = useState(false);
//控制更新弹窗出现
const [isUpdateModalVisible, setIsUpdateModalVisible] = useState(false);
//保存最新版本信息
const [versionData, setVersionData] = useState({});
useEffect(() => {
async function prepare() {
try {
const token = await get("token");
const account = await get("account");
const base = await baseRequest();
const signature = await generateSignature({
...base,
});
//检查当前token是否有效
if (token && account) {
const response = await fetch(
`${apiUrl}/api/login/validate?signature=${signature}`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
...base,
}),
}
);
const data = await response.json();
if (data.ret === 1) {
dispatch({ type: "SIGN_IN", token: token });
}
}
//检查更新
// const checkUpdataResponse = await fetch(
// `${apiUrl}/api/version/is_there_a_new_version_available?signature=${signature}`,
// {
// method: "POST",
// headers: {
// "Content-Type": "application/json",
// },
// body: JSON.stringify({
// ...base,
// }),
// }
// );
// const checkUpdataData = await checkUpdataResponse.json();
// if (checkUpdataData.ret === -1) {
// return;
// }
// if (checkUpdataData.data.result) {
// setIsUpdateModalVisible(true);
// setVersionData(checkUpdataData.data);
// }
} catch (e) {
console.warn(e);
} finally {
setAppIsReady(true);
}
}
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);
}, []);
//每次从后台切换到前台时,获取用户剪贴板内容
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();
}
}, [appIsReady]);
if (!appIsReady) {
return null;
}
return (
<TailwindProvider utilities={utilities}>
<AuthContext.Provider value={authContext}>
<SafeAreaProvider>
<StatusBar style="light" translucent />
<View style={{ flex: 1, backgroundColor: "#07050A" }}>
<NavigationContainer onReady={onLayoutRootView} theme={MyTheme}>
<RootStack.Navigator>
{state.isSignin ? (
<>
<RootStack.Screen
name="HomeTab"
component={HomeTab}
options={{
headerShown: false,
}}
/>
<RootStack.Screen
name="StreamerProfile"
component={StreamerProfile}
options={({ navigation }) => ({
headerLeft: () => (
<Icon
type="ionicon"
name="chevron-back"
size={32}
color="white"
onPress={() => navigation.goBack()}
/>
),
headerRight: () => (
<Icon
type="ionicon"
name="ellipsis-vertical"
size={32}
color="white"
/>
),
headerTransparent: true,
title: "",
})}
/>
<RootStack.Screen
name="UserProfile"
component={UserProfile}
options={({ navigation }) => ({
headerLeft: () => (
<Icon
type="ionicon"
name="chevron-back"
size={32}
color="white"
onPress={() => navigation.goBack()}
/>
),
headerTransparent: true,
title: "",
})}
/>
<RootStack.Screen
name="WechatWaitingToAdd"
component={WechatWaitingToAdd}
options={({ navigation }) => ({
headerLeft: () => (
<Icon
type="ionicon"
name="chevron-back"
size={32}
color="white"
onPress={() => navigation.goBack()}
/>
),
title: "待添加微信",
headerTitleStyle: { color: "white" },
headerStyle: { backgroundColor: "#07050A" },
})}
/>
<RootStack.Screen
name="MessageDetail"
component={MessageDetail}
options={({ navigation }) => ({
headerLeft: () => (
<Icon
type="ionicon"
name="chevron-back"
size={32}
color="white"
onPress={() => navigation.goBack()}
/>
),
title: "",
headerTitleStyle: { color: "white" },
headerStyle: { backgroundColor: "#07050A" },
})}
/>
<RootStack.Screen
name="EditUserProfile"
component={EditUserProfile}
options={{ headerShown: false }}
/>
<RootStack.Screen
name="Wallet"
component={Wallet}
options={({ navigation }) => ({
headerLeft: () => (
<Icon
type="ionicon"
name="chevron-back"
size={32}
color="white"
onPress={() => navigation.goBack()}
/>
),
headerTransparent: true,
title: "我的钱包",
headerTitleStyle: { color: "white" },
})}
/>
<RootStack.Screen
name="Setting"
component={Setting}
options={{ headerShown: false }}
/>
<RootStack.Screen
name="Relationship"
component={Relationship}
options={({ navigation }) => ({
headerLeft: () => (
<Icon
type="ionicon"
name="chevron-back"
size={32}
color="white"
onPress={() => navigation.goBack()}
/>
),
title: "关系",
headerTitleStyle: { color: "white" },
headerStyle: { backgroundColor: "#07050A" },
})}
/>
<RootStack.Screen
name="StreamerVerification"
component={StreamerVerification}
options={{ headerShown: false }}
/>
<RootStack.Screen
name="UnlockedWechat"
component={UnlockedWechat}
options={({ navigation }) => ({
headerLeft: () => (
<Icon
type="ionicon"
name="chevron-back"
size={32}
color="white"
onPress={() => navigation.goBack()}
/>
),
title: "已解锁微信",
headerTitleStyle: { color: "white" },
headerStyle: { backgroundColor: "#07050A" },
})}
/>
<RootStack.Screen
name="EditStreamerProfile"
component={EditStreamerProfile}
options={({ navigation }) => ({
headerLeft: () => (
<Icon
type="ionicon"
name="chevron-back"
size={32}
color="white"
onPress={() => navigation.goBack()}
/>
),
title: "编辑主页",
headerTitleStyle: { color: "white" },
headerStyle: { backgroundColor: "#07050A" },
})}
/>
<RootStack.Screen
name="EditPlatformOrder"
component={EditPlatformOrder}
options={({ navigation }) => ({
headerLeft: () => (
<Icon
type="ionicon"
name="chevron-back"
size={32}
color="white"
onPress={() => navigation.goBack()}
/>
),
title: "编辑平台",
headerTitleStyle: { color: "white" },
headerStyle: { backgroundColor: "#07050A" },
})}
/>
<RootStack.Screen
name="StreamerInviteUser"
component={StreamerInviteUser}
options={({ navigation }) => ({
headerLeft: () => (
<Icon
type="ionicon"
name="chevron-back"
size={32}
color="white"
onPress={() => navigation.goBack()}
/>
),
title: "邀请分成",
headerTitleStyle: { color: "white" },
headerStyle: { backgroundColor: "#07050A" },
})}
/>
<RootStack.Screen
name="Search"
component={Search}
options={{ headerShown: false }}
/>
<RootStack.Screen
name="WebWithHeader"
component={WebWithHeader}
options={({ navigation }) => ({
headerLeft: () => (
<Icon
type="ionicon"
name="chevron-back"
size={32}
color="white"
onPress={() => navigation.goBack()}
/>
),
headerTitleStyle: { color: "white" },
headerStyle: { backgroundColor: "#07050A" },
})}
/>
</>
) : (
<>
<RootStack.Screen
name="Login"
component={Login}
options={{ headerShown: false }}
/>
<RootStack.Screen
name="ForgetPassword"
component={ForgetPassword}
options={{ headerShown: false }}
/>
<RootStack.Screen
name="SetPassword"
component={SetPassword}
options={{ headerShown: false }}
/>
<RootStack.Screen
name="WebWithHeader"
component={WebWithHeader}
options={({ navigation }) => ({
headerLeft: () => (
<Icon
type="ionicon"
name="chevron-back"
size={32}
color="white"
onPress={() => navigation.goBack()}
/>
),
headerTitleStyle: { color: "white" },
headerStyle: { backgroundColor: "#07050A" },
})}
/>
</>
)}
</RootStack.Navigator>
<StreamerNavigatorModal
status={streamerNavigatorModalStatus}
setStatus={setStreamerNavigatorModalStatus}
/>
<PrivatyModal
visible={isPrivatyModalOpen}
setVisible={setIsPrivatyModalOpen}
confirm={() => {
setIsPrivatyModalOpen(false);
setChecked(true);
}}
/>
</NavigationContainer>
</View>
<Toast />
{/* <UpdateModal
visible={isUpdateModalVisible}
setVisible={setIsUpdateModalVisible}
data={versionData}
/> */}
</SafeAreaProvider>
</AuthContext.Provider>
</TailwindProvider>
);
}