diff --git a/MenuPage.js b/MenuPage.js
index 5102368..4e7647e 100644
--- a/MenuPage.js
+++ b/MenuPage.js
@@ -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() {
/>
)}
/>
+
-
+
);
}
diff --git a/Top.js b/Top.js
index 5f25b74..2925744 100644
--- a/Top.js
+++ b/Top.js
@@ -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}
/>
+
-
+
{
if (!props.payload) return <>>;
@@ -132,6 +133,11 @@ export const StationDeteilView = (props) => {
onExit={onExit}
/>
)}
+
{!currentStation[0].StationTimeTable || (
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) => {
+ const { navigate, onExit, currentStation } = props;
+ return (
+ }
+ flex={1}
+ onPressButton={() => {
+ navigate("stDiagram", {
+ currentStation,
+ });
+ onExit();
+ }}
+ >
+ 時刻表v2
+
+ );
+};
diff --git a/components/StationDiagram/ExGridView.tsx b/components/StationDiagram/ExGridView.tsx
new file mode 100644
index 0000000..9b3e230
--- /dev/null
+++ b/components/StationDiagram/ExGridView.tsx
@@ -0,0 +1,355 @@
+import { FC, useRef, useState, useCallback, useEffect } from "react";
+import {
+ View,
+ Text,
+ ScrollView,
+ useWindowDimensions,
+ Vibration,
+} from "react-native";
+import { ExGridViewItem } from "./ExGridViewItem";
+import Animated, {
+ useAnimatedStyle,
+ useSharedValue,
+ runOnJS,
+ useAnimatedScrollHandler,
+ withTiming,
+ Easing,
+ FadeIn,
+ FadeOut,
+ BounceInUp,
+ FadeInUp,
+ FadeOutUp,
+} from "react-native-reanimated";
+import { Gesture, GestureDetector } from "react-native-gesture-handler";
+import { ExGridViewTimePositionItem } from "./ExGridViewTimePositionItem";
+import { useCurrentTrain } from "@/stateBox/useCurrentTrain";
+import dayjs from "dayjs";
+type hoge = {
+ trainNumber: string;
+ array: string;
+ name: string;
+ timeType: string;
+ time: string;
+}[];
+export const ExGridView: FC<{
+ data: hoge;
+}> = ({ data }) => {
+ const groupedData: {
+ [d: number]: {
+ trainNumber: string;
+ array: string;
+ name: string;
+ timeType: string;
+ time: string;
+ isOperating: boolean;
+ }[];
+ } = {
+ "4": [],
+ "5": [],
+ "6": [],
+ "7": [],
+ "8": [],
+ "9": [],
+ "10": [],
+ "11": [],
+ "12": [],
+ "13": [],
+ "14": [],
+ "15": [],
+ "16": [],
+ "17": [],
+ "18": [],
+ "19": [],
+ "20": [],
+ "21": [],
+ "22": [],
+ "23": [],
+ "0": [],
+ "1": [],
+ "2": [],
+ "3": [],
+ };
+ const groupKeys = [
+ "4",
+ "5",
+ "6",
+ "7",
+ "8",
+ "9",
+ "10",
+ "11",
+ "12",
+ "13",
+ "14",
+ "15",
+ "16",
+ "17",
+ "18",
+ "19",
+ "20",
+ "21",
+ "22",
+ "23",
+ "0",
+ "1",
+ "2",
+ "3",
+ ];
+
+ const { width } = useWindowDimensions();
+ const { currentTrain } = useCurrentTrain();
+ data.forEach((item) => {
+ let isOperating = false;
+ let [hour, minute] = dayjs()
+ .hour(parseInt(item.time.split(":")[0]))
+ .minute(parseInt(item.time.split(":")[1]))
+ .format("H:m")
+ .split(":");
+ if (currentTrain.findIndex((x) => x.num == item.trainNumber) != -1) {
+ const currentTrainTime = currentTrain.find(
+ (x) => x.num == item.trainNumber
+ )?.delay;
+ if (currentTrainTime != "入線") {
+ [hour, minute] = dayjs()
+ .hour(parseInt(hour))
+ .minute(parseInt(minute))
+ .add(parseInt(currentTrainTime), "minute")
+ .format("H:m")
+ .split(":");
+ }
+ isOperating = true;
+ }
+ groupedData[hour].push({ ...item, time: `${hour}:${minute}`, isOperating });
+ });
+ // ドラッグ位置を保持する共有値
+ const widthX = useSharedValue(width);
+ const savedWidthX = useSharedValue(width);
+ const isChanging = useSharedValue(false);
+ const [scrollEnabled, setScrollEnabled] = useState(true);
+ const scrollRef = useRef(null);
+ const scrollRef2 = useRef(null);
+
+ // ScrollViewの有効/無効を切り替える関数
+ const toggleScrollEnabled = useCallback((enabled: boolean) => {
+ setScrollEnabled(enabled);
+ }, []);
+
+ // パンジェスチャー(ドラッグ)のハンドラー
+ const pinchGesture = Gesture.Pinch()
+ .onUpdate((e) => {
+ const calc = savedWidthX.value * e.scale;
+ widthX.value = calc > width ? calc : width;
+ //runOnJS(scrollToRightEnd)();
+ })
+ .onEnd(() => {
+ savedWidthX.value = widthX.value;
+ });
+
+ const gesture = Gesture.Pan()
+ .minPointers(2) // 最低2本指
+ .maxPointers(2) // 最大2本指
+ .onStart(() => {
+ runOnJS(toggleScrollEnabled)(false);
+ })
+ .onEnd(() => {
+ runOnJS(toggleScrollEnabled)(true);
+ savedWidthX.value = widthX.value;
+ });
+ const longPressGesture = Gesture.Pan()
+ .minPointers(1)
+ .maxPointers(1)
+ .activateAfterLongPress(200)
+ .onStart(() => {
+ runOnJS(Vibration.vibrate)(30);
+ isChanging.value = true;
+ })
+ .onUpdate((e) => {
+ const calc = widthX.value + e.velocityY;
+ widthX.value = calc > width ? calc : width;
+ })
+ .onEnd(() => {
+ console.log("Long press ended");
+ isChanging.value = false;
+ });
+
+ // ジェスチャーを組み合わせる
+ const composed = Gesture.Simultaneous(
+ longPressGesture,
+ pinchGesture,
+ gesture
+ );
+
+ // アニメーションスタイル
+ const animatedStyle = useAnimatedStyle(() => ({
+ width: widthX.value,
+ backgroundColor: isChanging.value ? "#8adeffff" : "white",
+ }));
+ // 時ヘッダーを横にスクロールしたときの処理
+ const scrollX = useSharedValue(0);
+ const scrollHandler = useAnimatedScrollHandler({
+ onScroll: (event) => {
+ scrollX.value = event.contentOffset.x;
+ },
+ });
+ const stickyTextStyle = useAnimatedStyle(() => ({
+ transform: [{ translateX: scrollX.value }],
+ }));
+ const animatedLongPressStyle = useAnimatedStyle(() => ({
+ display: isChanging.value ? "flex" : "none",
+ }));
+ useEffect(() => {
+ const getCurrentTime = dayjs().hour();
+ setTimeout(() => {
+ const keyTime =
+ getCurrentTime - 4 <= 0 ? getCurrentTime + 24 : getCurrentTime;
+ const goTo = keyTime * 60;
+ if (goTo > 400) {
+ scrollRef2.current?.scrollTo({ y: goTo - 300, animated: true });
+ }
+ }, 400);
+ }, [scrollRef2]);
+ return (
+ <>
+
+
+ ↑縮小 ・ 拡大↓
+
+
+
+ {
+ // 現在のスクロール位置を取得
+ const currentScrollX = scrollX.value;
+ const containerWidth = width - 50;
+
+ // コンテンツが画面からはみ出している場合のみ右端にスクロール
+ if (currentScrollX + containerWidth > contentWidth) {
+ const newScrollX = Math.max(0, contentWidth - containerWidth);
+ scrollRef.current?.scrollTo({ x: newScrollX, animated: true });
+ }
+ }}
+ ref={scrollRef}
+ contentContainerStyle={{
+ flexDirection: "column",
+ backgroundColor: "white",
+ }}
+ >
+
+ {Array.from({ length: 60 }, (_, i) => i + 1).map((num) => {
+ if (num % 5 === 0) {
+ return (
+
+ {num - 5}
+
+ );
+ } else return <>>;
+ })}
+
+ (分)
+
+
+ i * 2) : []
+ }
+ ref={scrollRef2}
+ >
+ {groupKeys.map((hour) => [
+
+
+ {hour}時台
+
+ ,
+
+ {groupedData[hour].map((d, i, array) => (
+
+ ))}
+
+ ,
+ ])}
+
+
+
+ >
+ );
+};
diff --git a/components/StationDiagram/ExGridViewItem.tsx b/components/StationDiagram/ExGridViewItem.tsx
new file mode 100644
index 0000000..db2a798
--- /dev/null
+++ b/components/StationDiagram/ExGridViewItem.tsx
@@ -0,0 +1,268 @@
+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, useLayoutEffect, useMemo, useState } from "react";
+import {
+ View,
+ Text,
+ TouchableOpacity,
+ useWindowDimensions,
+} 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";
+import { SharedValue, useAnimatedStyle } from "react-native-reanimated";
+import Animated from "react-native-reanimated";
+import lineColorList from "@/assets/originData/lineColorList";
+
+export const ExGridViewItem: FC<{
+ d: {
+ trainNumber: string;
+ array: string;
+ name: string;
+ timeType: string;
+ time: string;
+ isOperating: boolean;
+ };
+ index: number;
+ width: SharedValue;
+ array: {
+ train: string;
+ lastStation: string;
+ time: string;
+ isThrough?: boolean;
+ }[];
+}> = ({ d, index, width, array }) => {
+ const { allCustomTrainData } = useAllTrainDiagram();
+ const { originalStationList, stationList } = useStationList();
+ 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 [
+ 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:
+ // 行先がある場合は、行先を取得
+ const trainName = (d.timeType == "着" || d.timeType == "着編") ? trainData[0].split(",")[0] : trainData[trainData.length - 1].split(",")[0]
+ return [
+ typeString,
+ migrateTrainName(trainName),
+ 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("m");
+ let isSameTimeBefore = false;
+ if (index > 0) {
+ const beforeItem = array[index - 1];
+ const beforeTimeArray = beforeItem.time.split(":").map((s) => parseInt(s));
+ const beforeFormattedTime = dayjs()
+ .set("hour", beforeTimeArray[0])
+ .set("minute", beforeTimeArray[1])
+ .format("m");
+ isSameTimeBefore = beforeFormattedTime === formattedTime;
+ }
+
+ 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: d.isOperating ? null :"AllTrainIDList",
+ };
+ SheetManager.show("EachTrainInfo", {
+ //@ts-ignore
+ payload,
+ onClose: (data) => {
+ //alert(data);
+ },
+ });
+ };
+ const [stationColor, setStationColor] = useState(["gray"]);
+ useEffect(() => {
+ const Stations = stationList
+ .map((a) => a.filter((d) => d.StationName == trainName))
+ .reduce((newArray, e) => newArray.concat(e), []);
+ const StationNumbers =
+ Stations &&
+ Stations.filter((d) => d.StationNumber).map((d) => d.StationNumber);
+
+ if (StationNumbers) {
+ const stationLineColor = StationNumbers.map(
+ (d) => lineColorList[d.charAt(0)]
+ );
+ setStationColor(stationLineColor || ["gray"]);
+ }
+ }, [stationList]);
+ // if(typeString == "回送"){
+ // return<>>;
+ // }
+ const animatedStyle = useAnimatedStyle(() => {
+ const leftPosition =
+ ((((width.value - 50) / 100) * parseInt(formattedTime)) / 60) * 100;
+ return {
+ left: leftPosition,
+ };
+ }, [formattedTime]);
+ return (
+
+
+ openTrainInfo()}>
+
+ {formattedTime}
+
+ {d.timeType}
+
+
+
+
+ {trainName}
+
+
+
+
+
+ );
+};
diff --git a/components/StationDiagram/ExGridViewTimePositionItem.tsx b/components/StationDiagram/ExGridViewTimePositionItem.tsx
new file mode 100644
index 0000000..501a601
--- /dev/null
+++ b/components/StationDiagram/ExGridViewTimePositionItem.tsx
@@ -0,0 +1,44 @@
+import { FC } from "react";
+import { View } from "react-native";
+import dayjs from "dayjs";
+import { SharedValue, useAnimatedStyle } from "react-native-reanimated";
+import Animated from "react-native-reanimated";
+
+export const ExGridViewTimePositionItem: FC<{
+ width: SharedValue;
+ hour: string;
+}> = ({ width, hour }) => {
+ const date = dayjs();
+ const formattedTime = date.format("m");
+ const formattedHour = date.format("H");
+
+ // if(typeString == "回送"){
+ // return<>>;
+ // }
+ const animatedStyle = useAnimatedStyle(() => {
+ const leftPosition =
+ ((((width.value - 50) / 100) * parseInt(formattedTime)) / 60) * 100;
+ return {
+ left: leftPosition,
+ };
+ }, [formattedTime]);
+ if (formattedHour != hour) return <>>;
+ return (
+
+
+
+ );
+};
diff --git a/components/StationDiagram/ListView.tsx b/components/StationDiagram/ListView.tsx
new file mode 100644
index 0000000..1709333
--- /dev/null
+++ b/components/StationDiagram/ListView.tsx
@@ -0,0 +1,43 @@
+import { FC } from "react";
+import { ListViewItem } from "@/components/StationDiagram/ListViewItem";
+import { View, Text, ScrollView } from "react-native";
+
+export const ListView: FC<{
+ data: {
+ trainNumber: string;
+ array: string;
+ name: string;
+ type: string;
+ time: string;
+ }[];
+}> = ({ data }) => {
+ const groupedData = {};
+ const groupKeys = [];
+ data.forEach((item) => {
+ const hour = item.time.split(":")[0];
+ if (!groupedData[hour]) {
+ groupedData[hour] = [];
+ groupKeys.push(hour);
+ }
+ groupedData[hour].push(item);
+ });
+ return (
+ i * 2) : []
+ }
+ >
+ {groupKeys.map((hour) => [
+
+ {hour}時台
+ ,
+
+ {groupedData[hour].map((d, i) => (
+
+ ))}
+ ,
+ ])}
+
+ );
+};
diff --git a/components/StationDiagram/ListViewItem.tsx b/components/StationDiagram/ListViewItem.tsx
new file mode 100644
index 0000000..7e1e50e
--- /dev/null
+++ b/components/StationDiagram/ListViewItem.tsx
@@ -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 (
+ openTrainInfo()}
+ >
+
+ {formattedTime}
+
+ {d.type}
+
+
+
+
+
+ {typeString}
+
+
+ {trainData?.trainName +
+ (trainData?.trainNumDistance !== null
+ ? ` ${parseInt(d.trainNumber) - trainData?.trainNumDistance}号`
+ : "")}
+
+
+ {trainData?.TrainNumber}
+
+
+
+ {trainName}
+
+
+
+ );
+};
diff --git a/components/StationDiagram/StationDiagramView.tsx b/components/StationDiagram/StationDiagramView.tsx
new file mode 100644
index 0000000..3ce86ca
--- /dev/null
+++ b/components/StationDiagram/StationDiagramView.tsx
@@ -0,0 +1,454 @@
+import { FC, useEffect, useState } from "react";
+import {
+ View,
+ Text,
+ ScrollView,
+ TextInput,
+ Keyboard,
+ KeyboardAvoidingView,
+ Platform,
+ TouchableOpacity,
+ LayoutAnimation,
+} 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";
+import { ExGridView } from "./ExGridView";
+import { Switch } from "react-native-elements";
+import { customTrainDataDetector } from "../custom-train-data";
+import { typeID } from "@/lib/getStringConfig";
+import { colorString } from "@/lib/getTrainType";
+
+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 = ({ route }) => {
+ if (!route.params) {
+ return null;
+ }
+ const { currentStation } = route.params;
+ // 必要な情報:駅情報、全ダイヤ、カスタム列車情報
+ // 表示モード:縦並びリスト、横並びグリッド(時刻分割)、横並び単純左詰め
+ // フィルタリング:終点路線、種別、行先、関係停車駅
+
+ const { keyList, allTrainDiagram, allCustomTrainData } = useAllTrainDiagram();
+
+ const { navigate, addListener, goBack, canGoBack } = useNavigation();
+ const [keyBoardVisible, setKeyBoardVisible] = useState(false);
+ const [input, setInput] = useState("");
+ const [selectedTypeList, setSelectedTypeList] = useState([
+ "Normal",
+ "OneMan",
+ "Rapid",
+ "OneManRapid",
+ "LTDEXP",
+ "NightLTDEXP",
+ ]);
+ type hoge = {
+ trainNumber: string;
+ array: string;
+ name: string;
+ timeType: string;
+ time: string;
+ }[];
+ const [showTypeFiltering, setShowTypeFiltering] = useState(false);
+ const [showLastStop, setShowLastStop] = useState(false);
+ const [threw, setIsThrew] = useState(false);
+ const [currentStationDiagram, setCurrentStationDiagram] = useState([]);
+ useEffect(() => {
+ if (allTrainDiagram && currentStation.length > 0) {
+ const stationName = currentStation[0].Station_JP;
+ let returnDataArray: hoge = [];
+ keyList
+ .filter((s) => {
+ const boolData = allTrainDiagram[s];
+ let isStop = false;
+ let isInput = false;
+
+ boolData.split("#").forEach((d) => {
+ const [station, type, time] = d.split(",");
+ if (station === stationName) isStop = true;
+ if (station === input && type && !type.includes("通"))
+ isInput = true;
+ });
+ if (input && input.length > 0) {
+ return isInput && isStop;
+ }
+ return isStop;
+ })
+ .forEach((d) => {
+ allTrainDiagram[d]
+ .split("#")
+ .filter((d) => {
+ const [station, type, time] = d.split(",");
+ return station === stationName;
+ })
+ .forEach((x) => {
+ const [name, timeType, time] = x.split(",");
+ if (!name || !timeType || !time) return;
+
+ const { img, trainName, type, trainNumDistance, infogram } =
+ customTrainDataDetector(d, allCustomTrainData);
+ const arrayData = {
+ trainNumber: d,
+ array: allTrainDiagram[d],
+ name,
+ timeType,
+ time,
+ };
+ // //条件によってフィルタリング
+ if (!threw && timeType && timeType.includes("通")) return;
+ if (!showLastStop && timeType && timeType.includes("着")) return;
+ if (
+ selectedTypeList.length > 0 &&
+ selectedTypeList.findIndex((item) => item === type) === -1
+ ) {
+ if (
+ selectedTypeList.findIndex(
+ (item) => item === "Forwarding"
+ ) !== -1
+ ) {
+ if (!d.match(/[A,B,R,H,E,T,L]/)) return;
+ } else if (
+ selectedTypeList.findIndex((item) => item === "SPCL") !== -1
+ ) {
+ if (!d.match(/9\d\d\d[D,M,S]/)) return;
+ } else {
+ return;
+ }
+ }
+ 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;
+ })
+ );
+ }
+ }, [currentStation, showLastStop, threw, input, selectedTypeList]);
+
+ useEffect(() => {
+ const showSubscription = Keyboard.addListener("keyboardDidShow", () => {
+ setKeyBoardVisible(true);
+ });
+ const hideSubscription = Keyboard.addListener("keyboardDidHide", () => {
+ setKeyBoardVisible(false);
+ });
+
+ return () => {
+ showSubscription.remove();
+ hideSubscription.remove();
+ };
+ }, []);
+ return (
+
+
+ {currentStation[0].Station_JP}駅 時刻表
+
+ {/* */}
+
+ {/*
+ お気に入り登録した駅のうち、位置情報システムで移動可能な駅が表示されています。タップすることで位置情報システムの当該の駅に移動します。
+ */}
+
+
+ {
+ setIsThrew(!threw);
+ }}
+ >
+
+ 通過
+
+
+ {
+ setShowLastStop(!showLastStop);
+ }}
+ >
+
+ 当駅止
+
+
+
+ {showTypeFiltering ? (
+ <>
+
+
+
+
+
+
+ {
+ LayoutAnimation.configureNext(
+ LayoutAnimation.Presets.easeInEaseOut
+ );
+ setShowTypeFiltering(false);
+ }}
+ >
+
+ <
+
+
+ >
+ ) : (
+ {
+ LayoutAnimation.configureNext(
+ LayoutAnimation.Presets.easeInEaseOut
+ );
+ setShowTypeFiltering(true);
+ }}
+ >
+
+ >
+
+
+ )}
+
+
+ setKeyBoardVisible(true)}
+ onEndEditing={() => {}}
+ onChange={(ret) => setInput(ret.nativeEvent.text)}
+ value={input}
+ style={{ flex: 1 }}
+ />
+
+
+ {keyBoardVisible || (
+ goBack()} string="閉じる" />
+ )}
+
+ );
+};
+
+export const TypeSelectorBox: FC<{
+ selectedTypeList: typeID[];
+ setSelectedTypeList: (list: typeID[]) => void;
+ typeName: string;
+ typeID: typeID;
+ color: colorString;
+ relativeID?: typeID[];
+}> = (props) => {
+ const {
+ selectedTypeList,
+ setSelectedTypeList,
+ typeName,
+ typeID,
+ relativeID,
+ color,
+ } = props;
+ const isSelected =
+ selectedTypeList.findIndex((item) => item === typeID) !== -1;
+ return (
+ {
+ if (selectedTypeList.findIndex((item) => item === typeID) === -1) {
+ setSelectedTypeList([
+ ...selectedTypeList,
+ typeID,
+ ...(relativeID ?? []),
+ ]);
+ } else {
+ setSelectedTypeList(
+ selectedTypeList.filter(
+ (item) => item !== typeID && !relativeID?.includes(item)
+ )
+ );
+ }
+ }}
+ >
+
+ {typeName}
+
+
+ );
+};
diff --git a/lib/getStringConfig.ts b/lib/getStringConfig.ts
index 327c533..54f84a9 100644
--- a/lib/getStringConfig.ts
+++ b/lib/getStringConfig.ts
@@ -1,4 +1,4 @@
-type typeID =
+export type typeID =
| "Normal"
| "OneMan"
| "Rapid"
diff --git a/lib/getTrainType.ts b/lib/getTrainType.ts
index 7966b8a..99450f9 100644
--- a/lib/getTrainType.ts
+++ b/lib/getTrainType.ts
@@ -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";
+
+export 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",
+ };
}
};
diff --git a/stateBox/useAllTrainDiagram.js b/stateBox/useAllTrainDiagram.js
index a569f3d..a1f80de 100644
--- a/stateBox/useAllTrainDiagram.js
+++ b/stateBox/useAllTrainDiagram.js
@@ -6,6 +6,7 @@ const initialState = {
allTrainDiagram: undefined,
setAllTrainDiagram: () => {},
allCustomTrainData: [],
+ keyList: [],
};
const AllTrainDiagramContext = createContext(initialState);