完善消息通知
This commit is contained in:
parent
d1c2866f81
commit
2c75c47467
29
App.jsx
29
App.jsx
|
@ -69,7 +69,7 @@ import * as Clipboard from "expo-clipboard";
|
|||
import PrivatyModal from "./components/PrivatyModal";
|
||||
import * as Sentry from "@sentry/react-native";
|
||||
import { ImageViewerProvider } from "./context/ImageViewProvider";
|
||||
|
||||
import WebSocketComponent from "./components/Websocket";
|
||||
import store from "./store";
|
||||
import { Provider as ReduxProvider } from "react-redux";
|
||||
|
||||
|
@ -122,7 +122,6 @@ const App = () => {
|
|||
isSignin: false,
|
||||
userToken: null,
|
||||
});
|
||||
|
||||
const authContext = useMemo(
|
||||
() => ({
|
||||
signIn: async (data, mobilePhone, regionCode) => {
|
||||
|
@ -158,6 +157,7 @@ const App = () => {
|
|||
dispatch({ type: "SIGN_OUT" });
|
||||
}
|
||||
},
|
||||
state,
|
||||
inviterCode: inviterCode,
|
||||
checked: checked,
|
||||
setChecked: setChecked,
|
||||
|
@ -228,7 +228,25 @@ const App = () => {
|
|||
}
|
||||
prepare();
|
||||
}, []);
|
||||
|
||||
const handleGetWebsocketData = (data) => {
|
||||
if (data.d.unread_cnt > 0) {
|
||||
const { n_type, title } = data.d.notif;
|
||||
Toast.show({
|
||||
type: "info",
|
||||
text1: `🔔 收到一条${
|
||||
n_type === 0
|
||||
? "系统"
|
||||
: n_type === 1
|
||||
? "审核"
|
||||
: n_type === 2
|
||||
? "付费"
|
||||
: "活动"
|
||||
}通知`,
|
||||
text2: title,
|
||||
topOffset: 60,
|
||||
});
|
||||
}
|
||||
};
|
||||
//获取用户剪贴板内容
|
||||
const getClipboardContent = useCallback(async () => {
|
||||
const content = await Clipboard.getStringAsync();
|
||||
|
@ -242,7 +260,6 @@ const App = () => {
|
|||
}
|
||||
setInviterCode(null);
|
||||
}, []);
|
||||
|
||||
//登录后获取用户剪贴板内容
|
||||
useEffect(() => {
|
||||
if (!state.isSignin) return;
|
||||
|
@ -911,6 +928,10 @@ const App = () => {
|
|||
setVisible={setIsUpdateModalVisible}
|
||||
data={versionData}
|
||||
/>
|
||||
<WebSocketComponent
|
||||
getData={handleGetWebsocketData}
|
||||
state={state}
|
||||
/>
|
||||
</SafeAreaProvider>
|
||||
</ReduxProvider>
|
||||
</AuthContext.Provider>
|
||||
|
|
|
@ -2,86 +2,116 @@ import React, { useEffect, useState } from "react";
|
|||
import { View } from "react-native";
|
||||
import baseRequest from "../../utils/baseRequest";
|
||||
import { get } from "../../utils/storeInfo";
|
||||
import { getNoticeCount } from "../../store/reducer";
|
||||
import { connect } from "react-redux";
|
||||
import "text-encoding";
|
||||
const WebSocketComponent = ({ getData }) => {
|
||||
var retryInterval = 1000;
|
||||
const maxInterval = 60000;
|
||||
let interval = null;
|
||||
let timer = null;
|
||||
var messageQueue = [];
|
||||
let socket = null;
|
||||
const WebSocketComponent = ({ getData, state, changeCount }) => {
|
||||
const [messages, setMessages] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
let socket = null;
|
||||
let interval = null;
|
||||
async function connect_socket() {
|
||||
const appInfo = await get("app_info");
|
||||
const base = await baseRequest();
|
||||
if (socket && socket.readyState === 1) return;
|
||||
// 创建WebSocket连接
|
||||
if (!socket) {
|
||||
socket = new WebSocket(
|
||||
`${process.env.EXPO_PUBLIC_WEBSOCKET_URL}/ws?b_mid=${base.b_mid}&b_did=${base.b_did}&b_dt=1&b_token=${base.b_token}&b_ch${appInfo.b_ch}`
|
||||
);
|
||||
// console.log("------------++++++++++++++++", socket);
|
||||
socket.onopen = () => {
|
||||
console.log("WebSocket connected.");
|
||||
// 可以在这里发送消息到服务器,例如:socket.send('Hello Server!');
|
||||
socket.send(JSON.stringify({ t: 1 }));
|
||||
};
|
||||
|
||||
// 处理收到的消息
|
||||
socket.onmessage = (event) => {
|
||||
if (
|
||||
Object.prototype.toString.call(event.data) ===
|
||||
"[object ArrayBuffer]"
|
||||
) {
|
||||
let enc = new TextDecoder("utf-8");
|
||||
const view = new Uint8Array(event.data);
|
||||
let temp = enc.decode(view);
|
||||
try {
|
||||
const data = JSON.parse(temp);
|
||||
if (data.t === 2 && data.msg.ping_interval) {
|
||||
socket.send("ping");
|
||||
interval = setInterval(() => {
|
||||
// 发送 ping 给服务器
|
||||
socket.send("ping");
|
||||
// 响应服务器的 ping
|
||||
// socket.on("ping", () => {
|
||||
// socket.senrd("pong");
|
||||
// });
|
||||
}, data.msg.ping_interval * 1000);
|
||||
}
|
||||
if (data.t === 3) {
|
||||
getData(data.msg);
|
||||
setMessages((prevMessages) => [...prevMessages, data]);
|
||||
}
|
||||
} catch (error) {}
|
||||
}
|
||||
};
|
||||
|
||||
// 连接关闭时触发
|
||||
socket.onclose = () => {
|
||||
clearInterval(interval);
|
||||
// connect_socket();
|
||||
console.log("WebSocket disconnected.");
|
||||
};
|
||||
|
||||
// 连接错误时触发
|
||||
socket.onerror = (error) => {
|
||||
console.error("WebSocket error:", error);
|
||||
};
|
||||
}
|
||||
// 响应服务器的 ping
|
||||
// socket.on("ping", () => {
|
||||
// socket.send("pong");
|
||||
// });
|
||||
}
|
||||
|
||||
connect_socket();
|
||||
|
||||
// 组件卸载时关闭WebSocket连接
|
||||
return () => {
|
||||
console.log("卸载了socket");
|
||||
socket?.readyState === WebSocket.OPEN && socket?.close();
|
||||
clearInterval(interval);
|
||||
};
|
||||
}, []); // 空依赖数组表示这个effect只在组件挂载时运行一次
|
||||
useEffect(() => {
|
||||
socket?.close();
|
||||
if (state.isSignin) {
|
||||
connect_socket();
|
||||
} else {
|
||||
// changeCount(0);
|
||||
clearInterval(interval);
|
||||
clearTimeout(timer);
|
||||
socket?.close();
|
||||
socket = null;
|
||||
}
|
||||
}, [state]); // 空依赖数组表示这个effect只在组件挂载时运行一次
|
||||
async function connect_socket() {
|
||||
const appInfo = await get("app_info");
|
||||
const base = await baseRequest();
|
||||
if (socket && socket.readyState === 1) return;
|
||||
// 创建WebSocket连接
|
||||
socket = new WebSocket(
|
||||
`${process.env.EXPO_PUBLIC_WEBSOCKET_URL}/ws?b_mid=${base.b_mid}&b_did=${base.b_did}&b_dt=1&b_token=${base.b_token}&b_ch${appInfo.b_ch}`
|
||||
);
|
||||
socket.onopen = () => {
|
||||
console.log("WebSocket connected.");
|
||||
retryInterval = 1000;
|
||||
// 可以在这里发送消息到服务器,例如:socket.send('Hello Server!');
|
||||
if (socket.readyState == WebSocket.OPEN)
|
||||
socket.send(JSON.stringify({ t: 1 }));
|
||||
};
|
||||
|
||||
// 处理收到的消息
|
||||
socket.onmessage = (event) => {
|
||||
if (
|
||||
Object.prototype.toString.call(event.data) === "[object ArrayBuffer]"
|
||||
) {
|
||||
let enc = new TextDecoder("utf-8");
|
||||
const view = new Uint8Array(event.data);
|
||||
let temp = enc.decode(view);
|
||||
try {
|
||||
const data = JSON.parse(temp);
|
||||
if (data.t === 2 && data.msg.ping_interval) {
|
||||
if (socket.readyState == WebSocket.OPEN) socket.send("ping");
|
||||
interval = setInterval(() => {
|
||||
// 发送 ping 给服务器
|
||||
if (socket.readyState == WebSocket.OPEN) socket.send("ping");
|
||||
// 响应服务器的 ping
|
||||
// socket.on("ping", () => {
|
||||
// socket.senrd("pong");
|
||||
// });
|
||||
}, data.msg.ping_interval * 1000);
|
||||
}
|
||||
if (data.t === 3) {
|
||||
getData(data.msg);
|
||||
changeCount(data.msg.d.unread_cnt);
|
||||
setMessages((prevMessages) => [...prevMessages, data]);
|
||||
}
|
||||
} catch (error) {}
|
||||
}
|
||||
};
|
||||
|
||||
// 连接关闭时触发
|
||||
socket.onclose = async () => {
|
||||
clearTimeout(timer);
|
||||
const account = await get("account");
|
||||
if (state.isSignin && typeof account?.mid === "number") {
|
||||
timer = setTimeout(() => {
|
||||
if (!state.isSignin) {
|
||||
clearTimeout(timer);
|
||||
return;
|
||||
}
|
||||
retryInterval = Math.min(retryInterval * 2, maxInterval);
|
||||
try {
|
||||
connect_socket();
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}, retryInterval);
|
||||
}
|
||||
// changeCount(0);
|
||||
console.log("WebSocket disconnected.");
|
||||
};
|
||||
|
||||
// 连接错误时触发
|
||||
socket.onerror = (error) => {
|
||||
clearTimeout(timer);
|
||||
socket?.close();
|
||||
console.error("WebSocket error:", error);
|
||||
};
|
||||
// 响应服务器的 ping
|
||||
// socket.on("ping", () => {
|
||||
// socket.send("pong");
|
||||
// });
|
||||
}
|
||||
return (
|
||||
<View>
|
||||
{/* <Text style={{ fontSize: 24, fontWeight: 'bold' }}>WebSocket Messages</Text>
|
||||
|
@ -94,4 +124,13 @@ const WebSocketComponent = ({ getData }) => {
|
|||
);
|
||||
};
|
||||
|
||||
export default WebSocketComponent;
|
||||
const mapDispatchFromProps = (dispatch) => {
|
||||
return {
|
||||
changeCount: (num) => {
|
||||
// 调用dispatch方法,传递actions
|
||||
dispatch(getNoticeCount(num));
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export default connect(null, mapDispatchFromProps)(WebSocketComponent);
|
||||
|
|
|
@ -9,18 +9,15 @@ import Posts from "../Posts";
|
|||
import Space from "../Space";
|
||||
import { get } from "../../utils/storeInfo";
|
||||
import CreatePostModal from "../../components/CreatePostModal";
|
||||
import WebSocketComponent from "../../components/Websocket";
|
||||
import { connect } from "react-redux";
|
||||
import Toast from "react-native-toast-message";
|
||||
import baseRequest from "../../utils/baseRequest";
|
||||
import { generateSignature } from "../../utils/crypto";
|
||||
import { useSelector, useDispatch } from "react-redux";
|
||||
import { getNoticeCount } from "../../store/reducer";
|
||||
const Tab = createBottomTabNavigator();
|
||||
|
||||
export default function HomeTab({ navigation, route }) {
|
||||
function HomeTab({ changeCount, noticeCount, authInfo }) {
|
||||
const [isCreatePostTabVisible, setIsCreatePostTabVisible] = useState(false);
|
||||
const noticeCount = useSelector((state) => state.noticeCount);
|
||||
const dispatch = useDispatch();
|
||||
useEffect(() => {
|
||||
const checkRole = async () => {
|
||||
const account = await get("account");
|
||||
|
@ -51,10 +48,10 @@ export default function HomeTab({ navigation, route }) {
|
|||
});
|
||||
return;
|
||||
}
|
||||
dispatch(getNoticeCount(_data.data.total));
|
||||
changeCount(_data.data.total);
|
||||
};
|
||||
checkRole();
|
||||
}, [noticeCount]);
|
||||
}, [noticeCount, authInfo]);
|
||||
const CustomTabBarButton = useCallback(({ children }) => {
|
||||
const [visible, setVisible] = useState(false);
|
||||
return (
|
||||
|
@ -80,26 +77,6 @@ export default function HomeTab({ navigation, route }) {
|
|||
);
|
||||
}, []);
|
||||
|
||||
const handleGetWebsocketData = (data) => {
|
||||
if (data.d.unread_cnt > 0) {
|
||||
dispatch(getNoticeCount(data.d.unread_cnt));
|
||||
const { n_type, title } = data.d.notif;
|
||||
Toast.show({
|
||||
type: "info",
|
||||
text1: `🔔 收到一条${
|
||||
n_type === 0
|
||||
? "系统"
|
||||
: n_type === 1
|
||||
? "审核"
|
||||
: n_type === 2
|
||||
? "付费"
|
||||
: "活动"
|
||||
}通知`,
|
||||
text2: title,
|
||||
topOffset: 60,
|
||||
});
|
||||
}
|
||||
};
|
||||
const EmptyComponent = () => <></>;
|
||||
|
||||
return (
|
||||
|
@ -281,7 +258,26 @@ export default function HomeTab({ navigation, route }) {
|
|||
}}
|
||||
/>
|
||||
</Tab.Navigator>
|
||||
<WebSocketComponent getData={handleGetWebsocketData} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
// 获取store中的数据的方法
|
||||
const mapstateFromProps = (state) => {
|
||||
// state: store仓库中的数据
|
||||
return {
|
||||
noticeCount: state.noticeCount,
|
||||
authInfo: state.authInfo,
|
||||
};
|
||||
};
|
||||
// 修改store中的数据的方法
|
||||
const mapDispatchFromProps = (dispatch) => {
|
||||
return {
|
||||
changeCount: (num) => {
|
||||
// 调用dispatch方法,传递actions
|
||||
dispatch(getNoticeCount(num));
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export default connect(mapstateFromProps, mapDispatchFromProps)(HomeTab);
|
||||
|
|
|
@ -19,7 +19,8 @@ import { useDispatch } from "react-redux";
|
|||
import { getNoticeCount } from "../../../../store/reducer";
|
||||
import requireAPI from "../../../../utils/requireAPI";
|
||||
import { Image } from "expo-image";
|
||||
const MessageList = forwardRef(({ navigation }, ref) => {
|
||||
import { connect } from "react-redux";
|
||||
const MessageList = ({ navigation, noticeCount, refInstance }) => {
|
||||
const dispatch = useDispatch();
|
||||
const [data, setData] = useState([]);
|
||||
const [scollNotice, setScollNotice] = useState("");
|
||||
|
@ -59,7 +60,7 @@ const MessageList = forwardRef(({ navigation }, ref) => {
|
|||
icon: require(`../../../../assets/icon/others/m_active.png`),
|
||||
},
|
||||
]);
|
||||
useImperativeHandle(ref, () => ({
|
||||
useImperativeHandle(refInstance, () => ({
|
||||
readAllMsg: async (types) => {
|
||||
try {
|
||||
const body = {
|
||||
|
@ -98,11 +99,9 @@ const MessageList = forwardRef(({ navigation }, ref) => {
|
|||
},
|
||||
}));
|
||||
useEffect(() => {
|
||||
navigation.addListener("focus", () => {
|
||||
getData();
|
||||
getActiveNotice();
|
||||
});
|
||||
}, []);
|
||||
getData();
|
||||
getActiveNotice();
|
||||
}, [noticeCount]);
|
||||
const getData = async () => {
|
||||
try {
|
||||
const base = await baseRequest();
|
||||
|
@ -339,6 +338,17 @@ const MessageList = forwardRef(({ navigation }, ref) => {
|
|||
</View>
|
||||
</View>
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
export default MessageList;
|
||||
// 获取store中的数据的方法
|
||||
const mapstateFromProps = (state) => {
|
||||
// state: store仓库中的数据
|
||||
return {
|
||||
noticeCount: state.noticeCount,
|
||||
};
|
||||
};
|
||||
|
||||
const Component = connect(mapstateFromProps, null)(MessageList);
|
||||
export default forwardRef((props, ref) => (
|
||||
<Component {...props} refInstance={ref} />
|
||||
));
|
||||
|
|
|
@ -25,8 +25,9 @@ import baseRequest from "../../../utils/baseRequest";
|
|||
import { generateSignature } from "../../../utils/crypto";
|
||||
import MyModal from "../../../components/MyModal";
|
||||
import Toast from "react-native-toast-message";
|
||||
|
||||
export default function SwitchAccount({ navigation, route }) {
|
||||
import { handleLogin } from "../../../store/reducer";
|
||||
import { connect } from "react-redux";
|
||||
function SwitchAccount({ changeLogin }) {
|
||||
const blurhash = "LcKUTa%gOYWBYRt6xuoJo~s8V@fk";
|
||||
|
||||
const tailwind = useTailwind();
|
||||
|
@ -115,6 +116,12 @@ export default function SwitchAccount({ navigation, route }) {
|
|||
login_time: new Date().getTime(),
|
||||
});
|
||||
signIn(_data, data.mobile_phone_origion, data.region_code);
|
||||
changeLogin({
|
||||
isSignin: true,
|
||||
userToken: data.token,
|
||||
recommendMid: null,
|
||||
inviter: null,
|
||||
});
|
||||
setAccountList((pre) =>
|
||||
pre.map((item) => ({
|
||||
...item,
|
||||
|
@ -162,6 +169,12 @@ export default function SwitchAccount({ navigation, route }) {
|
|||
await remove(key);
|
||||
if (online) {
|
||||
signOut();
|
||||
changeLogin({
|
||||
isSignin: false,
|
||||
userToken: null,
|
||||
recommendMid: null,
|
||||
inviter: null,
|
||||
});
|
||||
return;
|
||||
}
|
||||
setAccountList((pre) => pre.filter((item) => item.key !== key));
|
||||
|
@ -316,3 +329,14 @@ export default function SwitchAccount({ navigation, route }) {
|
|||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
const mapDispatchFromProps = (dispatch) => {
|
||||
return {
|
||||
changeLogin: (data) => {
|
||||
// 调用dispatch方法,传递actions
|
||||
dispatch(handleLogin(data));
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export default connect(null, mapDispatchFromProps)(SwitchAccount);
|
||||
|
|
|
@ -5,14 +5,23 @@ export const appSlice = createSlice({
|
|||
initialState: {
|
||||
noticeCount: 0,
|
||||
},
|
||||
authInfo: {
|
||||
isSignin: false,
|
||||
userToken: null,
|
||||
recommendMid: null,
|
||||
inviter: null,
|
||||
},
|
||||
reducers: {
|
||||
getNoticeCount: (state, { payload }) => {
|
||||
state.noticeCount = payload;
|
||||
},
|
||||
handleLogin: (state, { payload }) => {
|
||||
state.authInfo = payload;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// Action creators are generated for each case reducer function
|
||||
export const { getNoticeCount } = appSlice.actions;
|
||||
export const { getNoticeCount, handleLogin } = appSlice.actions;
|
||||
|
||||
export default appSlice.reducer;
|
||||
|
|
Loading…
Reference in New Issue