Merge commit 'b867a788e2f0ca89735e426132683bc41c0d2c72' into develop

This commit is contained in:
harukin-expo-dev-env 2025-01-09 07:13:53 +00:00
commit 36be382b9f
5 changed files with 359 additions and 10 deletions

2
App.js
View File

@ -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,

View File

@ -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 (
<View style={{ height: "100%", backgroundColor: "#0099CC" }}>
<View style={{ backgroundColor: "#0099CC", flexDirection: "row" }}>
<View style={{ flex: 1 }}>
<TouchableOpacity
onPress={() => {
navigate("settingTopPage");
}}
style={{
flexDirection: "column",
flex: 1,
}}
>
<View style={{ flex: 1 }} />
<Text
style={{
fontSize: 20,
fontWeight: "bold",
textAlign: "left",
textAlignVertical: "center",
color: "white",
padding: 10,
}}
>
設定/送信
</Text>
<View style={{ flex: 1 }} />
</TouchableOpacity>
</View>
<Text
style={{
fontSize: 20,
fontWeight: "bold",
textAlign: "center",
color: "white",
padding: 10,
}}
>
通知設定(β)
</Text>
<View style={{ flex: 1 }}>
<TouchableOpacity
onPress={() => {
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,
}}
>
<View style={{ flex: 1 }} />
<Text
style={{
fontSize: 20,
fontWeight: "bold",
textAlign: "right",
textAlignVertical: "center",
color: "pink",
padding: 10,
}}
>
登録実行
</Text>
<View style={{ flex: 1 }} />
</TouchableOpacity>
</View>
</View>
<ScrollView style={{ flex: 1, backgroundColor: "white" }}>
<SimpleSwitch
bool={traInfoEX}
setBool={setTraInfoEX}
str="遅延速報EX"
/>
<SimpleSwitch
bool={informations}
setBool={setInformations}
str="運行情報"
/>
<SimpleSwitch
bool={strangeTrain}
setBool={setStrangeTrain}
str="怪レい列車"
/>
<Text style={{fontWeight: "bold", padding: 10 }} onPress={()=>{
Clipboard.setString(expoPushToken);
}}>
通知を受け取りたい項目を選択してくださいチェックボックスを選び右上の登録実行を押すと設定が反映され通知が届くようになります
</Text>
</ScrollView>
</View>
);
};
const SimpleSwitch = ({ bool, setBool, str }) => (
<View style={{ flexDirection: "row" }}>
<CheckBox
checked={bool == "true" ? true : false}
checkedColor="red"
onPress={() => setBool(bool == "true" ? "false" : "true")}
containerStyle={{
flex: 1,
backgroundColor: "#00000000",
borderColor: "white",
alignContent: "center",
}}
textStyle={{ fontSize: 20, fontWeight: "normal" }}
title={str}
/>
</View>
);

View File

@ -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 (
<View style={{ height: "100%", backgroundColor: "#0099CC" }}>
<View style={{ backgroundColor: "#0099CC", flexDirection: "row" }}>
@ -109,11 +117,11 @@ export const SettingTopPage = ({ navigate, testNFC,startPage,setStartPage, updat
trueImage={require("../../assets/configuration/showSetting1.jpg")}
falseText={"リンクメニュー"}
trueText={"列車位置情報"}
/><ListItem
/>
<ListItem
style={{ flexDirection: "row" }}
onPress={() => navigate("FavoriteSettings")}
>
<Text
style={{
fontSize: 20,
@ -138,6 +146,35 @@ export const SettingTopPage = ({ navigate, testNFC,startPage,setStartPage, updat
{">"}
</Text>
</ListItem>
<ListItem
style={{ flexDirection: "row" }}
onPress={() => navigate("NotificationSettings")}
disabled={expoPushToken == ""}
>
<Text
style={{
fontSize: 20,
alignItems: "center",
alignContent: "center",
textAlign: "center",
textAlignVertical: "center",
}}
>
通知設定{expoPushToken == "" ? "(通知設定をオンにしてください)" : "(β)"}
</Text>
<View style={{ flex: 1 }} />
<Text
style={{
fontSize: 20,
alignItems: "center",
alignContent: "center",
textAlign: "center",
textAlignVertical: "center",
}}
>
{">"}
</Text>
</ListItem>
<ListItem
style={{ flexDirection: "row" }}
onPress={() => navigate("LayoutSettings")}

View File

@ -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) {
/>
)}
</Stack.Screen>
<Stack.Screen
name="NotificationSettings"
options={{
//gestureEnabled: true,
...TransitionPresets.SlideFromRightIOS,
cardOverlayEnabled: true,
headerTransparent: true,
headerShown: false,
}}
>
{(props) => (
<NotificationSettings
{...props}
navigate={navigate}
/>
)}
</Stack.Screen>
<Stack.Screen
name="WidgetSettings"
options={{

View File

@ -0,0 +1,143 @@
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) {
console.log(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<initialStateType>(initialState);
type Props = {
children: React.ReactNode;
};
export const useNotification = () => {
return useContext(NotificationContext);
};
export const NotificationProvider: FC<Props> = ({ children }) => {
const [expoPushToken, setExpoPushToken] = useState("");
const [notification, setNotification] = useState<
Notifications.Notification | undefined
>(undefined);
const notificationListener = useRef<Notifications.EventSubscription>();
const responseListener = useRef<Notifications.EventSubscription>();
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);
};
}, []);
return (
<NotificationContext.Provider value={{ expoPushToken }}>
{children}
</NotificationContext.Provider>
);
};