diff --git a/App.js b/App.js index 9f27d9c..ddd4afe 100644 --- a/App.js +++ b/App.js @@ -17,6 +17,7 @@ import { DeviceOrientationChangeProvider } from "./stateBox/useDeviceOrientation import { TrainMenuProvider } from "./stateBox/useTrainMenu"; import { buildProvidersTree } from "./lib/providerTreeProvider"; import { StationListProvider } from "./stateBox/useStationList"; +import { NotificationProvider } from "./stateBox/useNotifications"; LogBox.ignoreLogs([ "ViewPropTypes will be removed", @@ -33,6 +34,7 @@ export default function App() { useEffect(() => UpdateAsync(), []); const ProviderTree = buildProvidersTree([ + NotificationProvider, StationListProvider, FavoriteStationProvider, TrainDelayDataProvider, diff --git a/stateBox/useNotifications.tsx b/stateBox/useNotifications.tsx new file mode 100644 index 0000000..88b60c7 --- /dev/null +++ b/stateBox/useNotifications.tsx @@ -0,0 +1,154 @@ +import React, { + createContext, + useContext, + useState, + useEffect, + FC, + useRef, +} from "react"; +// 6.0でライブラリ変更 +import { Platform, Clipboard } from "react-native"; +// 6.0でライブラリ更新、tsの型定義が変わった +import * as Notifications from "expo-notifications"; +import * as Device from "expo-device"; +import Constants from "expo-constants"; +type initialStateType = { + expoPushToken: string; +}; +const initialState = { + expoPushToken: "", +}; + +Notifications.setNotificationHandler({ + handleNotification: async () => ({ + shouldShowAlert: true, + shouldPlaySound: true, + shouldSetBadge: true, + }), +}); + +function handleRegistrationError(errorMessage: string) { + alert(errorMessage); + throw new Error(errorMessage); +} + +async function registerForPushNotificationsAsync() { + if (Platform.OS === "android") { + Notifications.setNotificationChannelAsync("default", { + name: "default", + importance: Notifications.AndroidImportance.MAX, + vibrationPattern: [0, 250, 250, 250], + lightColor: "#FF231F7C", + }); + Notifications.setNotificationChannelAsync("運行情報", { + name: "運行情報", + importance: Notifications.AndroidImportance.MAX, + vibrationPattern: [0, 250, 250, 250], + lightColor: "#FF231F7C", + }); + Notifications.setNotificationChannelAsync("遅延速報EX", { + name: "遅延速報EX", + importance: Notifications.AndroidImportance.MAX, + vibrationPattern: [0, 250, 250, 250], + lightColor: "#FF231F7C", + }); + Notifications.setNotificationChannelAsync("怪レい列車BOT", { + name: "怪レい列車BOT", + importance: Notifications.AndroidImportance.MAX, + vibrationPattern: [0, 250, 250, 250], + lightColor: "#FF231F7C", + }); + } + + if (Device.isDevice) { + const { status: existingStatus } = + await Notifications.getPermissionsAsync(); + let finalStatus = existingStatus; + if (existingStatus !== "granted") { + const { status } = await Notifications.requestPermissionsAsync(); + finalStatus = status; + } + if (finalStatus !== "granted") { + handleRegistrationError( + "Permission not granted to get push token for push notification!" + ); + return; + } + const projectId = + Constants?.expoConfig?.extra?.eas?.projectId ?? + Constants?.easConfig?.projectId; + if (!projectId) { + handleRegistrationError("Project ID not found"); + } + try { + const pushTokenString = ( + await Notifications.getExpoPushTokenAsync({ + projectId, + }) + ).data; + console.log(pushTokenString); + return pushTokenString; + } catch (e) { + handleRegistrationError(`${e}`); + } + } else { + handleRegistrationError("Must use physical device for push notifications"); + } +} +const NotificationContext = createContext(initialState); +type Props = { + children: React.ReactNode; +}; +export const useNotification = () => { + return useContext(NotificationContext); +}; + +export const NotificationProvider: FC = ({ children }) => { + const [expoPushToken, setExpoPushToken] = useState(""); + const [notification, setNotification] = useState< + Notifications.Notification | undefined + >(undefined); + const notificationListener = useRef(); + const responseListener = useRef(); + + useEffect(() => { + registerForPushNotificationsAsync() + .then((token) => setExpoPushToken(token ?? "")) + .catch((error) => setExpoPushToken(`${error}`)); + + notificationListener.current = + Notifications.addNotificationReceivedListener((notification) => { + setNotification(notification); + }); + + responseListener.current = + Notifications.addNotificationResponseReceivedListener((response) => { + console.log(response); + }); + + return () => { + notificationListener.current && + Notifications.removeNotificationSubscription( + notificationListener.current + ); + responseListener.current && + Notifications.removeNotificationSubscription(responseListener.current); + }; + }, []); + useEffect(() => { + if (expoPushToken) { + //alert(expoPushToken); + Clipboard.setString(expoPushToken); + //sendPushNotification(expoPushToken); + } + }, [expoPushToken]); + return ( + + {children} + + ); +};