424 lines
12 KiB
JavaScript
424 lines
12 KiB
JavaScript
import React, { useState, useEffect } from "react";
|
||
import { View, Text, TouchableOpacity } from "react-native";
|
||
import { widthPercentageToDP as wp } from "react-native-responsive-screen";
|
||
import { customTrainDataDetector } from "../custom-train-data";
|
||
import { useInterval } from "../../lib/useInterval";
|
||
import { objectIsEmpty } from "../../lib/objectIsEmpty";
|
||
import { getTrainType } from "../../lib/getTrainType";
|
||
import { getTrainDelayStatus } from "../../lib/getTrainDelayStatus";
|
||
import { checkDuplicateTrainData } from "../../lib/checkDuplicateTrainData";
|
||
import { useCurrentTrain } from "../../stateBox/useCurrentTrain";
|
||
import { useAreaInfo } from "../../stateBox/useAreaInfo";
|
||
import { SheetManager } from "react-native-actions-sheet";
|
||
import { AS } from "../../storageControl";
|
||
import { Footer } from "./LED_Vision_Component/Footer";
|
||
import { Header } from "./LED_Vision_Component/Header";
|
||
|
||
|
||
/**
|
||
*
|
||
* 1-30M しおかぜ
|
||
* 31-58D 南風
|
||
* 1001-1030M いしづち(併結)
|
||
* 1041-1046M いしづち(単独)
|
||
* 1051-1082D 宇和海
|
||
* 1091M MX松山
|
||
* 1092M MX高松
|
||
* 2001-2010D しまんと
|
||
* 2071-2086D あしずり
|
||
* 3001-3033D うずしお
|
||
* 3101-3177M マリンライナー
|
||
* 4001-4011D 剣山
|
||
* 5006,13,22,29 うずしお(岡山直通南風併結)
|
||
* 5831-5843D 土佐くろしお鉄道ごめん・なはり線直通快速
|
||
* 5853-5892D 土佐くろしお鉄道ごめん・なはり線直通普通
|
||
* 8011,8012D 四国まんなか千年ものがたり
|
||
* 8031,(8041) サンライズ瀬戸, 琴平(延長)
|
||
* 8053,8054D トキの夜明けのものがたり
|
||
* 8176,8179D アンパントロッコタカマツ
|
||
* 8277,8278D アンパントロッココトヒラ
|
||
* 8451,8452D よしの川トロッコ
|
||
* 8814,8819D しまんトロッコ
|
||
* 8911-8914D 伊予灘ものがたり
|
||
* 9001-9030* いしづち(リレー)
|
||
* 9031M サンライズ瀬戸琴平(延長)(臨時?)
|
||
* 9062D 四国まんなか千年ものがたり(臨時?)
|
||
*/
|
||
export default function LED_vision(props) {
|
||
const {
|
||
station,
|
||
trainDiagram,
|
||
getCurrentTrain,
|
||
navigate,
|
||
openStationACFromEachTrainInfo,
|
||
} = props;
|
||
const { currentTrain } = useCurrentTrain();
|
||
const [stationDiagram, setStationDiagram] = useState({}); //当該駅の全時刻表
|
||
const [finalSwitch, setFinalSwitch] = useState(false);
|
||
const [trainIDSwitch, setTrainIDSwitch] = useState(false);
|
||
const [trainDescriptionSwitch, setTrainDescriptionSwitch] = useState(false);
|
||
const [isInfoArea, setIsInfoArea] = useState(false);
|
||
const { areaInfo, areaStationID } = useAreaInfo();
|
||
|
||
useEffect(() => {
|
||
AS.getItem("LEDSettings/trainIDSwitch").then((data) => {
|
||
setTrainIDSwitch(data === "true");
|
||
});
|
||
AS.getItem("LEDSettings/trainDescriptionSwitch").then((data) => {
|
||
setTrainDescriptionSwitch(data == "true");
|
||
});
|
||
AS.getItem("LEDSettings/finalSwitch").then((data) => {
|
||
setFinalSwitch(data == "true");
|
||
});
|
||
}, []);
|
||
|
||
useEffect(() => {
|
||
// 現在の駅に停車するダイヤを作成する副作用[列車ダイヤと現在駅情報]
|
||
if (!trainDiagram) {
|
||
setStationDiagram({});
|
||
return;
|
||
}
|
||
let returnData = {};
|
||
Object.keys(trainDiagram).forEach((key) => {
|
||
if (trainDiagram[key].match(station[0].Station_JP + ",")) {
|
||
returnData[key] = trainDiagram[key];
|
||
}
|
||
});
|
||
setStationDiagram(returnData);
|
||
setIsInfoArea(station.some((s) => areaStationID.includes(s.StationNumber)));
|
||
}, [trainDiagram, station]);
|
||
|
||
const [trainTimeAndNumber, setTrainTimeAndNumber] = useState(null);
|
||
|
||
useEffect(() => {
|
||
//現在の駅に停車する列車から時刻を切り出してLEDベースにフォーマット
|
||
if (objectIsEmpty(stationDiagram)) return () => {};
|
||
const getTimeData = getTime(stationDiagram, station[0]);
|
||
setTrainTimeAndNumber(getTimeData);
|
||
}, [stationDiagram]);
|
||
|
||
const [selectedTrain, setSelectedTrain] = useState([]);
|
||
useEffect(() => {
|
||
if (!trainTimeAndNumber) return () => {};
|
||
if (!currentTrain) return () => {};
|
||
const data = trainTimeAndNumber
|
||
.filter((d) => currentTrain.map((m) => m.num).includes(d.train))
|
||
.filter(timeFiltering)
|
||
.filter((d) => !!finalSwitch || d.lastStation != "当駅止");
|
||
setSelectedTrain(data);
|
||
}, [trainTimeAndNumber, currentTrain, finalSwitch]);
|
||
|
||
const getTime = (stationDiagram, station) => {
|
||
const returnData = Object.keys(stationDiagram).map((trainNum) => {
|
||
let trainData = {};
|
||
stationDiagram[trainNum].split("#").forEach((data) => {
|
||
if (data.match("着")) {
|
||
trainData.lastStation = data.split(",着,")[0];
|
||
}
|
||
if (data.split(",")[0] === station.Station_JP) {
|
||
if (data.match(",発,")) {
|
||
trainData.time = data.split(",発,")[1];
|
||
} else {
|
||
trainData.time = data.split(",着,")[1];
|
||
trainData.lastStation = "当駅止";
|
||
}
|
||
}
|
||
});
|
||
return {
|
||
train: trainNum,
|
||
time: trainData.time,
|
||
lastStation: trainData.lastStation,
|
||
};
|
||
});
|
||
return returnData.sort((a, b) => {
|
||
switch (true) {
|
||
case parseInt(a.time.split(":")[0]) < parseInt(b.time.split(":")[0]):
|
||
return -1;
|
||
case parseInt(a.time.split(":")[0]) > parseInt(b.time.split(":")[0]):
|
||
return 1;
|
||
case parseInt(a.time.split(":")[1]) < parseInt(b.time.split(":")[1]):
|
||
return -1;
|
||
case parseInt(a.time.split(":")[1]) > parseInt(b.time.split(":")[1]):
|
||
return 1;
|
||
}
|
||
});
|
||
};
|
||
|
||
const timeFiltering = (d) => {
|
||
const date = new Date();
|
||
const newDate = new Date();
|
||
let data = d.time.split(":");
|
||
let delay = isNaN(currentTrain.filter((t) => t.num == d.train)[0].delay)
|
||
? 0
|
||
: currentTrain.filter((t) => t.num == d.train)[0].delay;
|
||
|
||
date.setHours(parseInt(data[0]));
|
||
date.setMinutes(parseInt(data[1]) + parseInt(delay));
|
||
return !(newDate > date);
|
||
};
|
||
|
||
const [areaString, setAreaString] = useState("");
|
||
const [areaStringLength, setAreaStringLength] = useState(0);
|
||
const [move, setMove] = useState(0);
|
||
useInterval(
|
||
() => {
|
||
if (areaInfo != "") {
|
||
setMove(areaStringLength < move ? 0 : move + 1);
|
||
}
|
||
},
|
||
350,
|
||
true
|
||
);
|
||
useEffect(() => {
|
||
if (!areaInfo) {
|
||
setAreaString("");
|
||
return () => {};
|
||
}
|
||
setAreaString(
|
||
areaInfo.substring(move, areaInfo.length) + areaInfo.substring(0, move)
|
||
);
|
||
}, [move]);
|
||
|
||
useEffect(() => {
|
||
if (!areaInfo) {
|
||
setAreaStringLength(0);
|
||
return () => {};
|
||
}
|
||
setAreaStringLength(areaInfo.length);
|
||
}, [areaInfo]);
|
||
|
||
return (
|
||
<View
|
||
style={{
|
||
width: wp("98%"),
|
||
/* height: wp("98%")/10*9, */ backgroundColor: "#432",
|
||
borderWidth: 1,
|
||
margin: 10,
|
||
marginHorizontal: wp("1%"),
|
||
}}
|
||
>
|
||
<Header getCurrentTrain={getCurrentTrain} />
|
||
{selectedTrain.map((d) => (
|
||
<EachData
|
||
{...{
|
||
d,
|
||
trainIDSwitch,
|
||
trainDescriptionSwitch,
|
||
customTrainDataDetector,
|
||
navigate,
|
||
openStationACFromEachTrainInfo,
|
||
}}
|
||
station={station[0]}
|
||
/>
|
||
))}
|
||
{areaString != "" && isInfoArea && (
|
||
<Description
|
||
numberOfLines={1}
|
||
info={areaString.replaceAll("\n", "").replaceAll("\r", "")}
|
||
onClick={() => alert(areaInfo)}
|
||
/>
|
||
)}
|
||
|
||
<Footer
|
||
{...{
|
||
trainIDSwitch,
|
||
setTrainIDSwitch,
|
||
trainDescriptionSwitch,
|
||
setTrainDescriptionSwitch,
|
||
finalSwitch,
|
||
setFinalSwitch,
|
||
}}
|
||
/>
|
||
</View>
|
||
);
|
||
}
|
||
|
||
const EachData = (props) => {
|
||
const {
|
||
d,
|
||
trainIDSwitch,
|
||
trainDescriptionSwitch,
|
||
station,
|
||
customTrainDataDetector,
|
||
navigate,
|
||
openStationACFromEachTrainInfo,
|
||
} = props;
|
||
const { currentTrain } = useCurrentTrain();
|
||
const openTrainInfo = (d) => {
|
||
let TrainNumber = "";
|
||
if (train.trainNumDistance != undefined) {
|
||
const timeInfo =
|
||
parseInt(d.train.replace("M", "").replace("D", "")) -
|
||
train.trainNumDistance;
|
||
TrainNumber = timeInfo + "号";
|
||
}
|
||
const payload = {
|
||
data: {
|
||
trainNum: d.train,
|
||
limited: `${getTrainType(train.type).data}:${
|
||
train.trainName
|
||
}${TrainNumber}`,
|
||
},
|
||
navigate,
|
||
openStationACFromEachTrainInfo,
|
||
from: "LED",
|
||
};
|
||
SheetManager.show("EachTrainInfo", {
|
||
payload,
|
||
});
|
||
};
|
||
const [train, setTrain] = useState(customTrainDataDetector(d.train));
|
||
useEffect(() => {
|
||
setTrain(customTrainDataDetector(d.train));
|
||
}, [currentTrain, d.train, trainDescriptionSwitch]);
|
||
// 土讃線複数存在対策
|
||
const currentTrainData = checkDuplicateTrainData(
|
||
currentTrain.filter((a) => a.num == d.train)
|
||
);
|
||
const trainDelayStatus = getTrainDelayStatus(
|
||
currentTrainData,
|
||
station.Station_JP
|
||
);
|
||
const trainPositionText = currentTrainData?.Pos.match("~")
|
||
? `現在地:${
|
||
currentTrainData?.Pos.replace("(下り)", "")
|
||
.replace("(上り)", "")
|
||
.split("~")[currentTrainData?.Direction == 1 ? 0 : 1]
|
||
}→${
|
||
currentTrainData?.Pos.replace("(下り)", "")
|
||
.replace("(上り)", "")
|
||
.split("~")[currentTrainData?.Direction == 1 ? 1 : 0]
|
||
}間を走行中`
|
||
: `現在地:${currentTrainData?.Pos}`;
|
||
return (
|
||
<>
|
||
<TouchableOpacity
|
||
style={{
|
||
alignContent: "center",
|
||
alignItems: "center",
|
||
width: "94%",
|
||
marginVertical: 5,
|
||
marginHorizontal: "3%",
|
||
backgroundColor: "#000",
|
||
flexDirection: "row",
|
||
}}
|
||
onPress={() => openTrainInfo(d)}
|
||
>
|
||
<TrainName
|
||
trainName={train.trainName}
|
||
trainNumDistance={train.trainNumDistance}
|
||
trainIDSwitch={trainIDSwitch}
|
||
trainID={d.train}
|
||
type={train.type}
|
||
/>
|
||
<LastStation lastStation={d.lastStation} />
|
||
<DependTime time={d.time} />
|
||
<StatusAndDelay trainDelayStatus={trainDelayStatus} />
|
||
</TouchableOpacity>
|
||
{trainDescriptionSwitch && <Description info={`${trainPositionText}`} />}
|
||
{trainDescriptionSwitch && !!train.info && (
|
||
<Description info={train.info} />
|
||
)}
|
||
</>
|
||
);
|
||
};
|
||
|
||
const TrainName = ({
|
||
trainName,
|
||
trainNumDistance,
|
||
trainIDSwitch,
|
||
trainID,
|
||
type,
|
||
}) => {
|
||
const { name, color } = getTrainType(type);
|
||
let TrainNumber =
|
||
trainNumDistance != undefined
|
||
? `${
|
||
parseInt(trainID.replace("M", "").replace("D", "")) - trainNumDistance
|
||
}号`
|
||
: "";
|
||
return (
|
||
<View style={{ flex: 9 }}>
|
||
<Text
|
||
style={{
|
||
fontSize: trainName.length > 6 ? parseInt("12%") : parseInt("16%"),
|
||
color: color,
|
||
fontWeight: "bold",
|
||
}}
|
||
>
|
||
{trainIDSwitch ? trainID : `${name} ${trainName}${TrainNumber}`}
|
||
</Text>
|
||
</View>
|
||
);
|
||
};
|
||
|
||
const LastStation = ({ lastStation }) => {
|
||
return (
|
||
<View style={{ flex: 4, flexDirection: "row" }}>
|
||
<Text
|
||
style={{
|
||
fontSize: lastStation.length > 4 ? parseInt("12%") : parseInt("16%"),
|
||
color: "white",
|
||
fontWeight: "bold",
|
||
}}
|
||
>
|
||
{lastStation}
|
||
</Text>
|
||
</View>
|
||
);
|
||
};
|
||
|
||
const descriptionStyle = {
|
||
fontSize: parseInt("16%"),
|
||
fontWeight: "bold",
|
||
};
|
||
|
||
const DependTime = ({ time }) => (
|
||
<View style={{ flex: 3 }}>
|
||
<Text style={{ ...descriptionStyle, color: "white" }}>{time}</Text>
|
||
</View>
|
||
);
|
||
|
||
const StatusAndDelay = ({ trainDelayStatus }) => {
|
||
return (
|
||
<View style={{ flex: 4 }}>
|
||
<Text style={{ ...descriptionStyle, color: "white", paddingLeft: 1 }}>
|
||
{trainDelayStatus}
|
||
</Text>
|
||
</View>
|
||
);
|
||
};
|
||
|
||
const Description = ({ info, numberOfLines = 0, onClick }) => (
|
||
<TouchableOpacity
|
||
style={{
|
||
alignContent: "center",
|
||
alignItems: "center",
|
||
width: "94%",
|
||
marginVertical: 5,
|
||
marginHorizontal: "3%",
|
||
backgroundColor: "#000",
|
||
flexDirection: "row",
|
||
overflow: "hidden",
|
||
}}
|
||
onPress={onClick}
|
||
>
|
||
<View style={{ flex: 4, flexDirection: "row" }}>
|
||
{numberOfLines == 1 ? (
|
||
<Text style={{ ...descriptionStyle, color: "red" }}>
|
||
運行情報 >{" "}
|
||
</Text>
|
||
) : (
|
||
<Text style={{ ...descriptionStyle, color: "green" }}> > </Text>
|
||
)}
|
||
|
||
<Text
|
||
style={{ ...descriptionStyle, color: "green" }}
|
||
numberOfLines={numberOfLines}
|
||
>
|
||
{info}
|
||
</Text>
|
||
</View>
|
||
</TouchableOpacity>
|
||
);
|