Merge commit '570a55f4307025eaad90d9bf617e82fa87cf24a1' into develop

This commit is contained in:
harukin-expo-dev-env 2025-07-03 12:08:53 +00:00
commit e6430c27a6
8 changed files with 196 additions and 55 deletions

30
GeneralWebView.tsx Normal file
View File

@ -0,0 +1,30 @@
import React, { CSSProperties } from "react";
import { View, ViewProps } from "react-native";
import { WebView } from "react-native-webview";
import { BigButton } from "./components/atom/BigButton";
import { useNavigation } from "@react-navigation/native";
export default ({ route }) => {
if (!route.params) {
return null;
}
const { uri, useExitButton = true } = route.params;
const { goBack } = useNavigation();
return (
<View style={styles}>
<WebView
useWebKit
source={{ uri }}
onMessage={(event) => {
const { data } = event.nativeEvent;
const {type} = JSON.parse(data);
if (type === "windowClose") return goBack();
}}
/>
{useExitButton && <BigButton onPress={goBack} string="閉じる" />}
</View>
);
};
const styles: ViewProps["style"] = {
height: "100%",
backgroundColor: "#0099CC",
};

View File

@ -18,6 +18,7 @@ import AllTrainDiagramView from "./components/AllTrainDiagramView";
import { useNavigation } from "@react-navigation/native";
import { news } from "./config/newsUpdate";
import { useBottomTabBarHeight } from "@react-navigation/bottom-tabs";
import GeneralWebView from "./GeneralWebView";
const Stack = createStackNavigator();
export function MenuPage() {
@ -128,6 +129,7 @@ export function MenuPage() {
component={AllTrainDiagramView}
/>
<Stack.Screen name="howto" options={optionData} component={HowTo} />
<Stack.Screen name="generalWebView" options={optionData} component={GeneralWebView} />
</Stack.Navigator>
);
}

2
Top.js
View File

@ -13,6 +13,7 @@ import { useTrainMenu } from "./stateBox/useTrainMenu";
import { AS } from "./storageControl";
import { news } from "./config/newsUpdate";
import { Linking, Platform } from "react-native";
import GeneralWebView from "./GeneralWebView";
const Stack = createStackNavigator();
export const Top = () => {
const { webview } = useCurrentTrain();
@ -64,6 +65,7 @@ export const Top = () => {
component={TrainBase}
/>
<Stack.Screen name="howto" options={optionData} component={HowTo} />
<Stack.Screen name="generalWebView" options={optionData} component={GeneralWebView} />
<Stack.Screen name="news" options={optionData} component={News} />
<Stack.Screen
name="trainMenu"

View File

@ -1,5 +1,5 @@
import React, { CSSProperties, FC, useEffect, useMemo, useState } from "react";
import { Text, View, LayoutAnimation, TextStyle } from "react-native";
import { Text, View, LayoutAnimation, TextStyle, TouchableOpacity } from "react-native";
import { Ionicons } from "@expo/vector-icons";
import { SheetManager } from "react-native-actions-sheet";
import { getType } from "../../../lib/eachTrainInfoCoreLib/getType";
@ -9,6 +9,8 @@ import { TrainViewIcon } from "./trainViewIcon";
import { OneManText } from "./HeaderTextParts/OneManText";
import { customTrainDataDetector } from "@/components/custom-train-data";
import { InfogramText } from "@/components/ActionSheetComponents/EachTrainInfoCore/HeaderTextParts/InfogramText";
import { useTrainMenu } from "@/stateBox/useTrainMenu";
import { useNotification } from "@/stateBox/useNotifications";
type Props = {
data: { trainNum: string; limited: string };
@ -42,6 +44,9 @@ export const HeaderText: FC<Props> = ({
}) => {
const { limited, trainNum } = data;
const { updatePermission } = useTrainMenu();
const {expoPushToken} = useNotification();
// 列車名、種別、フォントの取得
const [typeName, trainName, fontAvailable, isOneMan, infogram] =
useMemo(() => {
@ -120,8 +125,16 @@ export const HeaderText: FC<Props> = ({
return (
<View style={{ padding: 10, flexDirection: "row", alignItems: "center" }} onTouchStart={()=>scrollHandlers.ref.current?.scrollTo({ y: 0, animated: true })}>
<TrainIconStatus {...{ data, navigate, from }} />
<View
<TouchableOpacity
style={{ borderRadius: 5, flexDirection: "row", alignItems: "center" }}
onLongPress={() => {
navigate("generalWebView", {
uri: "https://jr-shikoku-data-post-system.pages.dev?trainNum=" + trainNum + "&token=" + expoPushToken,
useExitButton: false
});
SheetManager.hide("EachTrainInfo");
}}
disabled={!updatePermission}
>
<Text
style={{
@ -137,7 +150,7 @@ export const HeaderText: FC<Props> = ({
{isOneMan && <OneManText />}
<Text style={textConfig}>{trainName}</Text>
<InfogramText infogram={infogram} />
</View>
</TouchableOpacity>
<View style={{ flex: 1 }} />
<Text style={textConfig}>

View File

@ -1,5 +1,6 @@
import dayjs from "dayjs";
export const customTrainDataDetector = (TrainNumber: string) => {
const trainGetText = `?trainNum=${TrainNumber}&month=${dayjs().format("M")}&day=${dayjs().format("D")}`;
switch (TrainNumber) {
//しおかぜメイン
//8000 ノーマル
@ -49,7 +50,7 @@ export const customTrainDataDetector = (TrainNumber: string) => {
return {
type: "LTDEXP",
trainName: "しおかぜ",
trainIcon: `https://n8n.haruk.in/webhook/anpanman-pictures.png?trainNum=${TrainNumber}`,
trainIcon: `https://n8n.haruk.in/webhook/anpanman-pictures.png${trainGetText}`,
infoUrl: "https://www.jr-eki.com/aptrain/naani/yosan/train.html",
trainNumDistance: 0,
info: "いしづちと併結 / アンパンマン列車で運転",
@ -114,7 +115,7 @@ export const customTrainDataDetector = (TrainNumber: string) => {
return {
type: "LTDEXP",
trainName: "いしづち",
trainIcon: `https://n8n.haruk.in/webhook/anpanman-pictures.png?trainNum=${TrainNumber}`,
trainIcon: `https://n8n.haruk.in/webhook/anpanman-pictures.png${trainGetText}`,
infoUrl: "https://www.jr-eki.com/aptrain/naani/yosan/train.html",
trainNumDistance: 1000,
info: "しおかぜと併結 / アンパンマン列車で運転",
@ -173,7 +174,7 @@ export const customTrainDataDetector = (TrainNumber: string) => {
return {
type: "LTDEXP",
trainName: "いしづち",
trainIcon: `https://n8n.haruk.in/webhook/anpanman-pictures.png?trainNum=${TrainNumber}`,
trainIcon: `https://n8n.haruk.in/webhook/anpanman-pictures.png${trainGetText}`,
infoUrl: "https://www.jr-eki.com/aptrain/naani/yosan/train.html",
trainNumDistance: 940,
info: "アンパンマン列車で運転",
@ -247,7 +248,7 @@ export const customTrainDataDetector = (TrainNumber: string) => {
return {
type: "LTDEXP",
trainName: "南風",
trainIcon: `https://n8n.haruk.in/webhook/anpanman-pictures.png?trainNum=${TrainNumber}`,
trainIcon: `https://n8n.haruk.in/webhook/anpanman-pictures.png${trainGetText}`,
infoUrl: "https://www.jr-eki.com/aptrain/naani/dosan/train.html",
trainNumDistance: 30,
info: "アンパンマン列車で運転",
@ -587,7 +588,7 @@ export const customTrainDataDetector = (TrainNumber: string) => {
return {
type: "LTDEXP",
trainName: "宇和海",
trainIcon: `https://n8n.haruk.in/webhook/anpanman-pictures.png?trainNum=${TrainNumber}`,
trainIcon: `https://n8n.haruk.in/webhook/anpanman-pictures.png${trainGetText}`,
infoUrl: "https://www.jr-eki.com/aptrain/naani/yosan/train.html",
trainNumDistance: 1050,
info: "アンパン列車で運転",
@ -621,7 +622,7 @@ export const customTrainDataDetector = (TrainNumber: string) => {
return {
type: "LTDEXP",
trainName: "あしずり",
trainIcon: `https://n8n.haruk.in/webhook/anpanman-pictures.png?trainNum=${TrainNumber}`,
trainIcon: `https://n8n.haruk.in/webhook/anpanman-pictures.png${trainGetText}`,
infoUrl:
"https://www.jr-eki.com/aptrain/naani/first-generation/jikoku.html",
trainNumDistance: 2070,

View File

@ -30,10 +30,29 @@ export const injectJavascriptData: InjectJavascriptData = (
// 上部ヘッダーの取り扱い、自動再読み込み、setStringsの実行
const bootData = `
let stationList = {};
fetch("https://n8n.haruk.in/webhook/jr-shikoku-station-list").then((response) => response.json()).then((data) => {
stationList = data;
});
let trainDataList = [];
fetch("https://n8n.haruk.in/webhook/jr-shikoku-position-custom-datalist").then((response) => response.json()).then((data) => {
trainDataList = data[0].data;
}).then(()=>setReload());
let trainDiagramData2 = {};
fetch("https://n8n.haruk.in/webhook/JR-shikoku-diagram-migrate-original")
.then((response) => response.json())
.then((res)=>res.data)
.then((res) => {
const data = {};
res.forEach((d) => {
const keys = Object.keys(d);
data[keys] = d[keys];
});
return data;
})
.then((data) => {
trainDiagramData2 = data;
});
let probremsData = [];
fetch("https://n8n.haruk.in/webhook/jrshikoku-position-problems").then((response) => response.json()).then((data) => {
probremsData = data.data;
@ -54,7 +73,7 @@ export const injectJavascriptData: InjectJavascriptData = (
const trainIcon = `
const setStationIcon = (setIconElem,img,hasProblem) =>{
const position = setIconElem.getAttribute("style").includes("left");
setIconElem.insertAdjacentHTML('beforebegin', "<img src="+img+" style='float:"+(position ? 'left' : 'right')+";height:22px;'>");
setIconElem.insertAdjacentHTML('beforebegin', "<img src="+img+" style='float:"+(position ? 'left' : 'right')+";height:22px;margin: 2px;'>");
setIconElem.remove();
}
@ -1000,6 +1019,39 @@ export const injectJavascriptData: InjectJavascriptData = (
`;
const normal_train_name = `
const getJRF = num =>{
switch(num){
case "71":
return "東京(タ)→高松(タ)";
case "73":
case "75":
return "大阪(タ)→高松(タ)";
case "3079":
return "高松(タ)→伊予三島";
case "3071":
case "3077":
return "高松(タ)→新居浜";
case "3073":
return "高松(タ)→松山貨物";
case "70":
return "高松(タ)→東京(タ)";
case "74":
case "76":
return "高松(タ)→大阪(タ)";
case "3078":
return "伊予三島→高松(タ)";
case "3070":
return "新居浜→高松(タ)";
case "3076":
return "新居浜→高松(タ)";
case "3072":
return "松山貨物→高松(タ)";
case "9070":
return "臨時貨物";
default:
return undefined;
}
}
const nameReplace = (,,,hasProblem) =>{
let isWanman = false;
let trainName = "";
@ -1008,12 +1060,11 @@ export const injectJavascriptData: InjectJavascriptData = (
let TrainNumber = ;
try{
const diagram = trainTimeInfo[];
const diagram = trainDiagramData2[] || trainTimeInfo[];
if(diagram){
const diagramData = diagram.split("#");
ToData = diagramData[diagramData.length - 2].split(",")[0];
}
}catch(e){}
if(.split(":")[1]){
const textBase = .split(":")[1].replace("\\r","");
@ -1041,42 +1092,20 @@ export const injectJavascriptData: InjectJavascriptData = (
else if(.indexOf("R") != -1){
trainName = "回送";
}
else if(.indexOf("E") != -1){
trainName = "回送";
}
else if(.indexOf("A") != -1){
trainName = "回送";
}
else if(.indexOf("B") != -1){
trainName = "回送";
}
else if(.indexOf("S") != -1){
trainName = "臨時列車";
}
const getJRF = num =>{
switch(num){
case "71":
return "東京(タ)→高松(タ)";
case "73":
case "75":
return "大阪(タ)→高松(タ)";
case "3079":
return "高松(タ)→伊予三島";
case "3071":
case "3077":
return "高松(タ)→新居浜";
case "3073":
return "高松(タ)→松山貨物";
case "70":
return "高松(タ)→東京(タ)";
case "74":
case "76":
return "高松(タ)→大阪(タ)";
case "3078":
return "伊予三島→高松(タ)";
case "3070":
return "新居浜→高松(タ)";
case "3076":
return "新居浜→高松(タ)";
case "3072":
return "松山貨物→高松(タ)";
case "9070":
return "臨時貨物";
}
}
let JRF = true;
const JRFTemp = getJRF();
@ -1250,9 +1279,27 @@ export const injectJavascriptData: InjectJavascriptData = (
const returnText2 = (ToData ? ToData+"行 " : ToData)+ TrainNumber;
.innerText = "";
${uiSetting === "tokyo" ? `
.insertAdjacentHTML('beforebegin', "<p style='font-size:10px;font-weight:bold;padding:0;color:black;text-align:center;'>" + (ToData ? ToData + "行 " : ToData) + "</p>");
.insertAdjacentHTML('beforebegin', "<p style='font-size:8px;font-weight:bold;padding:0;color: black;text-align:center;'>" + returnText1 + "</p>");
.insertAdjacentHTML('beforebegin', "<p style='font-size:8px;padding:0;color:black;text-align:center;'>" + TrainNumber + (JRF ? "":"レ") + "</p>");
let stationIDs = [];
let stationLines = [];
Object.keys(stationList).forEach((key) => {
const data = stationList[key].find(e => e.Station_JP === ToData )?.StationNumber;
if(data){
stationIDs.push(data);
stationLines.push(key);
}
});
let getColors = [];
if(stationLines.length === 0){
getColors = ["#000"];
}else{
getColors = stationLines.map(e => GetLineBarColor(e));
}
const gradient = getColors.length > 1 ? "linear-gradient(130deg, " + getColors[0] + " 0%, "+ getColors[0]+"50%, "+ getColors[1]+"50%, " + getColors[1] + " 100%)" : getColors[0];
.insertAdjacentHTML('beforebegin', "<p style='font-size:6px;padding:0;color:black;text-align:center;'>" + TrainNumber + (JRF ? "":"レ") + "</p>");
.insertAdjacentHTML('beforebegin', "<p style='font-size:8px;font-weight:bold;padding:0;color: black;text-align:center;'>" + (isWanman ? "ワンマン " : "") + "</p>");
.insertAdjacentHTML('beforebegin', "<p style='font-size:6px;font-weight:bold;padding:0;color: black;text-align:center;'>" + viaData + "</p>");
.insertAdjacentHTML('beforebegin', "<p style='font-size:8px;font-weight:bold;padding:0;color: black;text-align:center;'>" + trainName + "</p>");
.insertAdjacentHTML('beforebegin', "<div style='width:100%;background:" + gradient + ";'><p style='font-size:10px;font-weight:bold;padding:0;margin:0;color:white;align-items:center;align-content:center;text-align:center;text-shadow:1px 1px 0px #00000030, -1px -1px 0px #00000030,-1px 1px 0px #00000030, 1px -1px 0px #00000030,1px 0px 0px #00000030, -1px 0px 0px #00000030,0px 1px 0px #00000030, 0px -1px 0px #00000030;'>" + (ToData ? ToData + "行" : ToData) + "</p></div>");
.insertAdjacentHTML('beforebegin', "<p style='font-size:8px;font-weight:bold;padding:0;text-align:center;color: "+(hasProblem ? "red":"black")+";'>" + (hasProblem ? "‼️停止中‼️" : "") + "</p>");
`: `
.insertAdjacentHTML('beforebegin', "<p style='font-size:10px;font-weight:bold;padding:0;color: black;'>" + returnText1 + "</p>");
@ -1266,13 +1313,39 @@ export const injectJavascriptData: InjectJavascriptData = (
`
const setNewTrainItem = (element)=>{
element.style.borderColor = 'white';
const setNewTrainItem = (element,hasProblem)=>{
var = element.getAttribute('offclick').split('"')[1];
const JRFTemp = getJRF();
if(element.getAttribute('offclick').includes("express")){
element.style.borderColor = 'rgba(255, 0, 0, 1)';
}else if(element.getAttribute('offclick').includes("rapid")){
element.style.borderColor = 'rgba(0, 140, 255, 1)';
}else if(JRFTemp){
element.style.borderColor = 'rgba(0, 134, 158, 0.8)';
}else{
element.style.borderColor = 'white';
}
element.style.borderWidth = '2px';
element.style.borderStyle = 'solid';
element.style.borderRadius = '10%';
element.style.backgroundColor = 'rgba(255, 255, 255, 0.8)';
element.style.boxShadow = '0 0 4px rgba(0, 0, 0, 0.2)';
switch(true){
case .indexOf("H") != -1:
case .indexOf("R") != -1:
case .indexOf("E") != -1:
case .indexOf("A") != -1:
case .indexOf("B") != -1:
case !!JRFTemp:
element.style.backgroundColor = 'rgba(199, 199, 199, 0.8)';
break;
default:
element.style.backgroundColor = 'rgba(255, 255, 255, 0.8)';
break;
}
if(hasProblem){
element.style.boxShadow = '0 0 10px rgba(255, 0, 0, 0.9)';
}else{
element.style.boxShadow = '0 0 4px rgba(0, 0, 0, 0.2)';
}
element.style.margin = '2px';
element.style.display = 'flex';
element.style.alignItems = 'center';
@ -1287,12 +1360,12 @@ const setNewTrainItem = (element)=>{
element.addEventListener('touchend', () => element.style.transform = 'scale(1)');
if(element.getAttribute("style").includes("left")){
// borderを使って五角形を生成 下り
element.style.borderRadius = '20% 20% 80% 80%';
element.style.borderRadius = '10% 10% 40% 40%';
element.style.flexDirection = 'column-reverse';
}
else if(element.getAttribute("style").includes("right")){
// borderを使って五角形を生成 上り
element.style.borderRadius = '80% 80% 20% 20%';
element.style.borderRadius = '40% 40% 10% 10%';
element.style.flexDirection = 'column';
}
@ -1387,7 +1460,7 @@ const setStrings = () =>{
}
` : ""}
nameReplace(,,,hasProblem);
${uiSetting === "tokyo" ? `setNewTrainItem(element);`: ``}
${uiSetting === "tokyo" ? `setNewTrainItem(element,hasProblem);`: ``}
}
try{
for(let d of document.getElementById('disp').childNodes){

View File

@ -54,13 +54,13 @@ export default function Menu(props) {
}, []);
const mapsRef = useRef(null);
const returnToTop = (bool = true) => {
scrollRef.current.scrollTo({
scrollRef?.current.scrollTo({
y: mapHeight > 80 ? mapHeight - 80 : 0,
animated: bool,
});
};
const goToMap = () => {
scrollRef.current.scrollTo({
scrollRef?.current.scrollTo({
y: 0,
animated: true,
});

View File

@ -5,6 +5,8 @@ import { ASCore } from "../storageControl";
import { getStationList2 } from "../lib/getStationList";
import { injectJavascriptData } from "../lib/webViewInjectjavascript";
import { useNotification } from "../stateBox/useNotifications";
const initialState = {
selectedLine: undefined,
setSelectedLine: () => {},
@ -28,6 +30,8 @@ const initialState = {
setTrainInfo: () => {},
trainMenu: "true",
setTrainMenu: () => {},
updatePermission : false,
setUpdatePermission : () => {},
injectJavascript: "",
};
@ -38,6 +42,7 @@ export const useTrainMenu = () => {
};
export const TrainMenuProvider = ({ children }) => {
const { expoPushToken } = useNotification();
const [selectedLine, setSelectedLine] = useState(undefined);
const [mapsStationData, setMapsStationData] = useState(undefined);
useEffect(() => {
@ -50,6 +55,19 @@ export const TrainMenuProvider = ({ children }) => {
const [stationMenu, setStationMenu] = useState(undefined);
const [LoadError, setLoadError] = useState(false);
//更新権限所有確認
const [updatePermission, setUpdatePermission] = useState(false);
useEffect(()=>{
fetch("https://n8n.haruk.in/webhook/data-edit-permission?token=" + expoPushToken).then((res)=>res.json())
.then((res)=>{
if(res.data == true){
setUpdatePermission(true);
}else{
setUpdatePermission(false);
}
})
}, [expoPushToken])
//列車情報表示関連
const [trainInfo, setTrainInfo] = useState({
trainNum: undefined,
@ -106,6 +124,8 @@ export const TrainMenuProvider = ({ children }) => {
setTrainInfo,
trainMenu,
setTrainMenu,
updatePermission,
setUpdatePermission,
injectJavascript,
}}
>