From 54e76a86f3f150c2307ff61ed13a628bd6c13322 Mon Sep 17 00:00:00 2001 From: harukin-expo-dev-env Date: Tue, 7 Jan 2025 06:46:11 +0000 Subject: [PATCH 1/2] =?UTF-8?q?=E9=80=9A=E7=9F=A5=E6=A9=9F=E8=83=BD?= =?UTF-8?q?=E3=81=AE=E4=BB=AE=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App.js | 2 + stateBox/useNotifications.tsx | 154 ++++++++++++++++++++++++++++++++++ 2 files changed, 156 insertions(+) create mode 100644 stateBox/useNotifications.tsx 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} + + ); +}; From b867a788e2f0ca89735e426132683bc41c0d2c72 Mon Sep 17 00:00:00 2001 From: harukin-expo-dev-env Date: Thu, 9 Jan 2025 07:13:42 +0000 Subject: [PATCH 2/2] =?UTF-8?q?=E7=94=BB=E9=9D=A2=E6=95=B4=E5=82=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/Settings/NotificationSettings.js | 149 ++++++++++++++++++++ components/Settings/SettingTopPage.js | 57 ++++++-- components/Settings/settings.js | 18 +++ stateBox/useNotifications.tsx | 17 +-- 4 files changed, 217 insertions(+), 24 deletions(-) create mode 100644 components/Settings/NotificationSettings.js diff --git a/components/Settings/NotificationSettings.js b/components/Settings/NotificationSettings.js new file mode 100644 index 0000000..f0c5352 --- /dev/null +++ b/components/Settings/NotificationSettings.js @@ -0,0 +1,149 @@ +import React, { useEffect, useState } from "react"; +import { View, Text, TouchableOpacity, ScrollView,Clipboard } from "react-native"; + +import { CheckBox } from "react-native-elements"; +import { AS } from "../../storageControl"; +import { useNotification } from "../../stateBox/useNotifications"; + +export const NotificationSettings = ({ navigate }) => { + const { expoPushToken } = useNotification(); + const [traInfoEX, setTraInfoEX] = useState(false); + const [informations, setInformations] = useState(false); + const [strangeTrain, setStrangeTrain] = useState(false); + useEffect(() => { + AS.getItem("traInfoEX").then(setTraInfoEX); + AS.getItem("informations").then(setInformations); + AS.getItem("strangeTrain").then(setStrangeTrain); + }, []); + + return ( + + + + { + navigate("settingTopPage"); + }} + style={{ + flexDirection: "column", + flex: 1, + }} + > + + + < 設定/送信 + + + + + + + 通知設定(β) + + + { + fetch( + "https://n8n.haruk.in/webhook/jr-shikoku-notification-configurations", + { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + token: expoPushToken, + traInfoEX, + informations, + strangeTrain, + }), + } + ).then(() => { + Promise.all([ + AS.setItem("traInfoEX", traInfoEX.toString()), + AS.setItem("informations", informations.toString()), + AS.setItem("strangeTrain", strangeTrain.toString()), + ]).then(()=>alert("通知の設定を保存、登録しました")); + }); + }} + style={{ + flexDirection: "column", + flex: 1, + }} + > + + + 登録実行 + + + + + + + + + + { + Clipboard.setString(expoPushToken); + }}> + 通知を受け取りたい項目を選択してください。チェックボックスを選び、右上の「登録実行」を押すと設定が反映され、通知が届くようになります。 + + + + ); +}; + +const SimpleSwitch = ({ bool, setBool, str }) => ( + + setBool(bool == "true" ? "false" : "true")} + containerStyle={{ + flex: 1, + backgroundColor: "#00000000", + borderColor: "white", + alignContent: "center", + }} + textStyle={{ fontSize: 20, fontWeight: "normal" }} + title={str} + /> + +); diff --git a/components/Settings/SettingTopPage.js b/components/Settings/SettingTopPage.js index 382de1b..40a007f 100644 --- a/components/Settings/SettingTopPage.js +++ b/components/Settings/SettingTopPage.js @@ -12,11 +12,19 @@ import * as Updates from "expo-updates"; import { useWindowDimensions } from "react-native"; import { ListItem } from "native-base"; import { SwitchArea } from "../atom/SwitchArea"; +import { useNotification } from "../../stateBox/useNotifications"; const versionCode = "5.5.1"; -export const SettingTopPage = ({ navigate, testNFC,startPage,setStartPage, updateAndReload }) => { +export const SettingTopPage = ({ + navigate, + testNFC, + startPage, + setStartPage, + updateAndReload, +}) => { const { width } = useWindowDimensions(); + const { expoPushToken } = useNotification(); return ( @@ -102,18 +110,18 @@ export const SettingTopPage = ({ navigate, testNFC,startPage,setStartPage, updat + navigate("FavoriteSettings")} > - "} + navigate("NotificationSettings")} + disabled={expoPushToken == ""} + > + + 通知設定{expoPushToken == "" ? "(通知設定をオンにしてください)" : "(β)"} + + + + {">"} + + navigate("LayoutSettings")} diff --git a/components/Settings/settings.js b/components/Settings/settings.js index 4f9004f..d375630 100644 --- a/components/Settings/settings.js +++ b/components/Settings/settings.js @@ -22,6 +22,7 @@ import { SettingTopPage } from "./SettingTopPage"; import { LayoutSettings } from "./LayoutSettings"; import { FavoriteSettings } from "./FavoriteSettings"; import { WidgetSettings } from "./WidgetSettings"; +import { NotificationSettings } from "./NotificationSettings"; const Stack = createStackNavigator(); export default function Setting(props) { @@ -118,6 +119,23 @@ export default function Setting(props) { /> )} + + {(props) => ( + + )} + = ({ children }) => { Notifications.removeNotificationSubscription(responseListener.current); }; }, []); - useEffect(() => { - if (expoPushToken) { - //alert(expoPushToken); - Clipboard.setString(expoPushToken); - //sendPushNotification(expoPushToken); - } - }, [expoPushToken]); return ( - + {children} );