駅時刻表のコア情報を作成

This commit is contained in:
harukin-expo-dev-env
2025-08-25 15:54:40 +00:00
parent 2f558cddb2
commit c00034a11b
9 changed files with 484 additions and 20 deletions

View File

@@ -19,6 +19,7 @@ import { useNavigation } from "@react-navigation/native";
import { news } from "./config/newsUpdate";
import { useBottomTabBarHeight } from "@react-navigation/bottom-tabs";
import GeneralWebView from "./GeneralWebView";
import { StationDiagramView } from "@/components/StationDiagram/StationDiagramView";
const Stack = createStackNavigator();
export function MenuPage() {
@@ -86,7 +87,7 @@ export function MenuPage() {
})
.catch((error) => {
if (__DEV__) {
console.warn('お気に入り駅の読み込みに失敗しました:', error);
console.warn("お気に入り駅の読み込みに失敗しました:", error);
}
});
});
@@ -112,6 +113,11 @@ export function MenuPage() {
/>
)}
/>
<Stack.Screen
name="stDiagram"
options={{ ...optionData, gestureEnabled: false }}
component={StationDiagramView}
/>
<Stack.Screen name="news" options={optionData} component={News} />
<Stack.Screen
name="setting"
@@ -133,7 +139,11 @@ export function MenuPage() {
component={AllTrainDiagramView}
/>
<Stack.Screen name="howto" options={optionData} component={HowTo} />
<Stack.Screen name="generalWebView" options={optionData} component={GeneralWebView} />
<Stack.Screen
name="generalWebView"
options={optionData}
component={GeneralWebView}
/>
</Stack.Navigator>
);
}

15
Top.js
View File

@@ -14,6 +14,7 @@ import { AS } from "./storageControl";
import { news } from "./config/newsUpdate";
import { Linking, Platform } from "react-native";
import GeneralWebView from "./GeneralWebView";
import { StationDiagramView } from "@/components/StationDiagram/StationDiagramView";
const Stack = createStackNavigator();
export const Top = () => {
const { webview } = useCurrentTrain();
@@ -37,7 +38,8 @@ export const Top = () => {
return;
}
if (!isFocused()) navigate("positions", { screen: "Apps" });
else if (mapSwitch == "true") navigate("positions", { screen: "trainMenu" });
else if (mapSwitch == "true")
navigate("positions", { screen: "trainMenu" });
else webview.current?.injectJavaScript(`AccordionClassEvent()`);
return;
};
@@ -64,8 +66,17 @@ export const Top = () => {
options={{ ...optionData }}
component={TrainBase}
/>
<Stack.Screen
name="stDiagram"
options={{ ...optionData, gestureEnabled: false }}
component={StationDiagramView}
/>
<Stack.Screen name="howto" options={optionData} component={HowTo} />
<Stack.Screen name="generalWebView" options={optionData} component={GeneralWebView} />
<Stack.Screen
name="generalWebView"
options={optionData}
component={GeneralWebView}
/>
<Stack.Screen name="news" options={optionData} component={News} />
<Stack.Screen
name="trainMenu"

View File

@@ -19,6 +19,7 @@ import { 駅構内図 } from "./StationDeteilView/StationInsideMapButton";
import { WebSiteButton } from "./StationDeteilView/WebSiteButton";
import { StationTimeTableButton } from "./StationDeteilView/StationTimeTableButton";
import { StationTrainPositionButton } from "./StationDeteilView/StationTrainPositionButton";
import { StationDiagramButton } from "./StationDeteilView/StationDiagramButton";
export const StationDeteilView = (props) => {
if (!props.payload) return <></>;
@@ -132,6 +133,11 @@ export const StationDeteilView = (props) => {
onExit={onExit}
/>
)}
<StationDiagramButton
navigate={navigate}
onExit={onExit}
currentStation={currentStation}
/>
{!currentStation[0].StationTimeTable || (
<StationTimeTableButton
info={info}

View File

@@ -0,0 +1,40 @@
import React, { FC } from "react";
import { Linking } from "react-native";
import { FontAwesome } from "@expo/vector-icons";
import { TicketBox } from "@/components/atom/TicketBox";
type Props = {
navigate: (screen: string, params?: object) => void;
onExit: () => void;
currentStation: {
Station_JP: string;
Station_EN: string;
StationName?: string;
MyStation?: string;
StationNumber: string;
DispNum?: string;
StationTimeTable: string;
StationMap?: string;
JrHpUrl?: string;
lat: number;
lng: number;
jslodApi: string;
}[];
};
export const StationDiagramButton: FC<Props> = (props) => {
const { navigate, onExit, currentStation } = props;
return (
<TicketBox
backgroundColor={"#8F5902"}
icon={<FontAwesome name="table" color="white" size={50} />}
flex={1}
onPressButton={() => {
navigate("stDiagram", {
currentStation,
});
onExit();
}}
>
v2
</TicketBox>
);
};

View File

@@ -0,0 +1,18 @@
import { FC } from "react";
import { ListViewItem } from "@/components/StationDiagram/ListViewItem";
export const ListView: FC<{ data: {
trainNumber: string;
array: string;
name: string;
type: string;
time: string;
}[]; }> = ({ data }) => {
return (
<>
{data.map((d, i) => (
<ListViewItem key={d.trainNumber + i} d={d} />
))}
</>
);
};

View File

@@ -0,0 +1,244 @@
import { migrateTrainName } from "@/lib/eachTrainInfoCoreLib/migrateTrainName";
import { getStringConfig, typeID } from "@/lib/getStringConfig";
import { getTrainType } from "@/lib/getTrainType";
import { useAllTrainDiagram } from "@/stateBox/useAllTrainDiagram";
import { FC, useEffect, useMemo, useState } from "react";
import { View, Text, TouchableOpacity } from "react-native";
import { customTrainDataDetector } from "../custom-train-data";
import dayjs from "dayjs";
import { SheetManager } from "react-native-actions-sheet";
import { useNavigation } from "@react-navigation/native";
import { lineList } from "@/lib/getStationList";
import { useStationList } from "@/stateBox/useStationList";
export const ListViewItem: FC<{
d: {
trainNumber: string;
array: string;
name: string;
type: string;
time: string;
};
}> = ({ d }) => {
const { allCustomTrainData } = useAllTrainDiagram();
const { navigate, goBack } = useNavigation();
const [trainData, setTrainData] = useState<{
ToData: string;
TrainNumber: string;
id: string;
img: string;
info?: string;
infoUrl: string;
infogram: string;
isEdit: boolean;
isSeason: boolean;
trainName: string;
trainNumDistance?: number;
type: typeID;
viaData?: string;
uwasa?: string;
}>();
useEffect(() => {
if (allCustomTrainData) {
allCustomTrainData.forEach((x) => {
if (x.TrainNumber === d.trainNumber) {
setTrainData(x);
}
});
}
}, []);
const { color, name, data } = getTrainType(trainData?.type, true);
const { originalStationList } = useStationList();
// 列車名、種別、フォントの取得
const [
typeString,
trainName,
fontAvailable,
isOneMan,
infogram,
isEdit,
uwasa,
vehicleFormation,
trainInfoUrl,
] = useMemo(() => {
const {
type,
trainName,
trainNumDistance,
infogram,
isEdit,
uwasa,
vehicleFormation,
trainInfoUrl,
} = customTrainDataDetector(d.trainNumber, allCustomTrainData);
const [typeString, fontAvailable, isOneMan] = getStringConfig(
type,
d.trainNumber
);
const trainData = d.array.split("#").filter((d) => d !== "");
switch (true) {
case trainData[trainData.length - 1] === undefined:
return [
typeString,
"",
fontAvailable,
isOneMan,
infogram,
isEdit,
uwasa,
vehicleFormation,
trainInfoUrl,
];
default:
// 行先がある場合は、行先を取得
return [
typeString,
migrateTrainName(
trainData[trainData.length - 1].split(",")[0] + "行き"
),
fontAvailable,
isOneMan,
infogram,
isEdit,
uwasa,
vehicleFormation,
trainInfoUrl,
];
}
}, [d.array]);
const timeArray = d.time.split(":").map((s) => parseInt(s));
const formattedTime = dayjs()
.set("hour", timeArray[0])
.set("minute", timeArray[1])
.format("HH:mm");
const openStationACFromEachTrainInfo = async (stationName) => {
await SheetManager.hide("EachTrainInfo");
const findStationEachLine = (selectLine) => {
let NearStation = selectLine.filter((d) => d.Station_JP == stationName);
return NearStation;
};
let returnDataBase = lineList
.map((d) => findStationEachLine(originalStationList[d]))
.filter((d) => d.length > 0)
.reduce((pre, current) => {
pre.push(...current);
return pre;
}, []);
if (returnDataBase.length) {
const payload = {
currentStation: returnDataBase,
navigate,
//@ts-ignore
useShow: () => SheetManager.show("StationDetailView", { payload }),
onExit: () => SheetManager.hide("StationDetailView"),
};//@ts-ignore
setTimeout(() => SheetManager.show("StationDetailView", { payload }), 50);
} else {
SheetManager.hide("StationDetailView");
}
};
const openTrainInfo = () => {
let TrainNumber = "";
if (trainData.trainNumDistance != undefined) {
const timeInfo =
parseInt(trainData.TrainNumber.replace("M", "").replace("D", "")) -
trainData.trainNumDistance;
TrainNumber = timeInfo + "号";
}
const payload = {
data: {
trainNum: trainData.TrainNumber,
limited: `${data}:${trainData.trainName}${TrainNumber}`,
},
navigate,
openStationACFromEachTrainInfo,
from: "AllTrainIDList",
};
SheetManager.show("EachTrainInfo", {
//@ts-ignore
payload,
onClose: (data) => {
//alert(data);
},
});
};
return (
<TouchableOpacity
style={{
flexDirection: "row",
marginHorizontal: 10,
borderTopWidth: 1,
borderBottomWidth: 0.5,
borderStyle: "solid",
borderColor: "darkgray",
padding: 10,
opacity: d.type.includes("通") ? 0.5 : 1,
}}
onPress={() => openTrainInfo()}
>
<View style={{ position: "relative" }}>
<Text style={{ fontSize: 30 }}>{formattedTime}</Text>
<Text
style={{
fontSize: 10,
position: "absolute",
bottom: -3,
right: 0,
fontWeight: "bold",
}}
>
{d.type}
</Text>
</View>
<View style={{ flex: 1, flexDirection: "column" }}>
<View style={{ flexDirection: "row" }}>
<Text
style={{
fontSize: 15,
fontFamily: fontAvailable ? "JR-Nishi" : undefined,
fontWeight: !fontAvailable ? "bold" : undefined,
paddingTop: fontAvailable ? 2 : 0,
paddingLeft: 10,
color: color,
}}
>
{typeString}
</Text>
<Text
style={{
fontSize: 15,
fontWeight: "bold",
flex: 1,
paddingLeft: 2,
color: color,
}}
>
{trainData?.trainName +
(trainData?.trainNumDistance !== null
? ` ${parseInt(d.trainNumber) - trainData?.trainNumDistance}`
: "")}
</Text>
<Text
style={{
fontSize: 15,
fontWeight: "bold",
}}
>
{trainData?.TrainNumber}
</Text>
</View>
<Text
style={{
fontSize: 15,
flex: 1,
paddingHorizontal: 10,
fontWeight: "bold",
}}
>
{trainName}
</Text>
</View>
</TouchableOpacity>
);
};

View File

@@ -0,0 +1,114 @@
import { FC, useEffect, useState } from "react";
import { View, Text, ScrollView } from "react-native";
import { useNavigation } from "@react-navigation/native";
import { BigButton } from "../atom/BigButton";
import { useAllTrainDiagram } from "@/stateBox/useAllTrainDiagram";
import { ListView } from "@/components/StationDiagram/ListView";
import dayjs from "dayjs";
type props = {
route: {
params: {
currentStation: {
Station_JP: string;
Station_EN: string;
StationName?: string;
MyStation?: string;
StationNumber: string;
DispNum?: string;
StationTimeTable: string;
StationMap?: string;
JrHpUrl?: string;
lat: number;
lng: number;
jslodApi: string;
}[];
};
};
};
export const StationDiagramView: FC<props> = ({ route }) => {
if (!route.params) {
return null;
}
const { currentStation } = route.params;
// 必要な情報:駅情報、全ダイヤ、カスタム列車情報
// 表示モード:縦並びリスト、横並びグリッド(時刻分割)、横並び単純左詰め
// フィルタリング:終点路線、種別、行先、関係停車駅
const { allTrainDiagram } = useAllTrainDiagram();
const { navigate, addListener, goBack, canGoBack } = useNavigation();
type hoge = {
trainNumber: string;
array: string;
name: string;
type: string;
time: string;
}[];
const [currentStationDiagram, setCurrentStationDiagram] = useState<hoge>([]);
useEffect(() => {
if (allTrainDiagram && currentStation.length > 0) {
const stationName = currentStation[0].Station_JP;
let returnDataArray = [];
Object.keys(allTrainDiagram).forEach((d) => {
if (allTrainDiagram[d].includes(stationName)) {
allTrainDiagram[d]
.split("#")
.filter((d) => d.includes(stationName))
.forEach((x) => {
const [name, type, time] = x.split(",");
if (!name || !type || !time) return;
const arrayData = {
trainNumber: d,
array: allTrainDiagram[d],
name,
type,
time,
};
returnDataArray.push(arrayData);
});
}
});
setCurrentStationDiagram(returnDataArray.sort((a, b) => {
const adjustTime = (t: string) => {
const [h, m] = t.split(":").map(Number);
// 4時未満は翌日の時刻とみなして+24時間
return h < 4 ? dayjs().add(1, "day").hour(h).minute(m) : dayjs().hour(h).minute(m);
};
const aa = adjustTime(a.time);
const bb = adjustTime(b.time);
const x = aa.isAfter(bb);
return x ? 1 : -1;
//return true;
}));
}
}, []);
return (
<View style={{ height: "100%", backgroundColor: "#0099CC" }}>
<Text
style={{
textAlign: "center",
fontSize: 20,
color: "white",
fontWeight: "bold",
paddingVertical: 10,
}}
>
{currentStation[0].Station_JP}
</Text>
<ScrollView style={{ backgroundColor: "white" }}>
<ListView data={currentStationDiagram} />
</ScrollView>
{/* <Text
style={{
backgroundColor: "white",
borderWidth: 1,
borderStyle: "solid",
}}
>
お気に入り登録した駅のうち、位置情報システムで移動可能な駅が表示されています。タップすることで位置情報システムの当該の駅に移動します。
</Text> */}
<BigButton onPress={() => goBack()} string="閉じる" />
</View>
);
};

View File

@@ -1,4 +1,4 @@
type typeID =
export type typeID =
| "Normal"
| "OneMan"
| "Rapid"

View File

@@ -1,11 +1,17 @@
type nameString =
| "Rapid"
| "LTDEXP"
| "NightLTDEXP"
| "SPCL"
| "Normal"
| string;
type colorString = "aqua" | "red" | "#297bff" | "#ff7300ff" | "#00869ecc" | "#727272cc" | "white" | "pink";
import { typeID } from "./getStringConfig";
type colorString =
| "aqua"
| "red"
| "#297bff"
| "#ff7300ff"
| "#00869ecc"
| "#727272cc"
| "#00b8d8cc"
| "#e000b0ff"
| "white"
| "black"
| "pink";
type trainTypeString =
| "快速"
| "特急"
@@ -21,24 +27,35 @@ type trainTypeString =
| "単機回送"
| "その他";
type trainTypeDataString = "rapid" | "express" | "normal" | "notService";
type getTrainType = (d: nameString) => {
type getTrainType = (
d: typeID,
isWhiteMode?: boolean
) => {
color: colorString;
name: trainTypeString;
data: trainTypeDataString;
};
export const getTrainType: getTrainType = (nameString) => {
export const getTrainType: getTrainType = (nameString, whiteMode) => {
switch (nameString) {
case "Normal":
return { color: "white", name: "普通列車", data: "normal" };
return {
color: whiteMode ? "black" : "white",
name: "普通列車",
data: "normal",
};
case "OneMan":
return { color: "white", name: "普通列車(ワンマン)", data: "normal" };
return {
color: whiteMode ? "black" : "white",
name: "普通列車(ワンマン)",
data: "normal",
};
case "Rapid":
case "OneManRapid":
return { color: "aqua", name: "快速", data: "rapid" };
return { color: whiteMode ? "#00b8d8cc" : "aqua", name: "快速", data: "rapid" };
case "LTDEXP":
return { color: "red", name: "特急", data: "express" };
case "NightLTDEXP":
return { color: "pink", name: "寝台特急", data: "express" };
return { color: whiteMode ? "#e000b0ff":"pink", name: "寝台特急", data: "express" };
case "SPCL":
case "SPCL_Normal":
return { color: "#297bff", name: "臨時", data: "normal" };
@@ -55,6 +72,10 @@ export const getTrainType: getTrainType = (nameString) => {
case "FreightForwarding":
return { color: "#727272cc", name: "単機回送", data: "notService" };
default:
return { color: "white", name: "その他", data: "normal" };
return {
color: whiteMode ? "black" : "white",
name: "その他",
data: "normal",
};
}
};