526 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			526 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| import React, { useEffect, useState } from "react";
 | |
| import {
 | |
|   View,
 | |
|   Text,
 | |
|   TouchableOpacity,
 | |
|   StyleSheet,
 | |
|   useWindowDimensions,
 | |
|   BackHandler,
 | |
|   Linking,
 | |
|   LayoutAnimation,
 | |
| } from "react-native";
 | |
| import { SheetManager } from "react-native-actions-sheet";
 | |
| import { useScrollHandlers } from "react-native-actions-sheet";
 | |
| import { AS } from "../../storageControl";
 | |
| import { lineListPair, stationIDPair } from "../../lib/getStationList";
 | |
| import { useCurrentTrain } from "../../stateBox/useCurrentTrain";
 | |
| import { checkDuplicateTrainData } from "../../lib/checkDuplicateTrainData";
 | |
| import { getTrainType } from "../../lib/getTrainType";
 | |
| import { customTrainDataDetector } from "../custom-train-data";
 | |
| import { useBusAndTrainData } from "../../stateBox/useBusAndTrainData";
 | |
| import { useDeviceOrientationChange } from "../../stateBox/useDeviceOrientationChange";
 | |
| import { EachStopList } from "./EachTrainInfo/EachStopList";
 | |
| import { DataFromButton } from "./EachTrainInfo/DataFromButton";
 | |
| import { DynamicHeaderScrollView } from "../DynamicHeaderScrollView";
 | |
| import { LongHeader } from "./EachTrainInfo/LongHeader";
 | |
| import { ShortHeader } from "./EachTrainInfo/ShortHeader";
 | |
| import { ScrollStickyContent } from "./EachTrainInfo/ScrollStickyContent";
 | |
| import { getStationID } from "../../lib/eachTrainInfoCoreLib/getStationData";
 | |
| import { findReversalPoints } from "../../lib/eachTrainInfoCoreLib/findReversalPoints";
 | |
| import { searchSpecialTrain } from "../../lib/eachTrainInfoCoreLib/searchSpecialTrain";
 | |
| import { openBackTrainInfo } from "../../lib/eachTrainInfoCoreLib/openBackTrainInfo";
 | |
| import { ShowSpecialTrain } from "./EachTrainInfo/ShowSpecialTrain";
 | |
| import { useTrainMenu } from "../../stateBox/useTrainMenu";
 | |
| import { HeaderText } from "./EachTrainInfoCore/HeaderText";
 | |
| import { useStationList } from "../../stateBox/useStationList";
 | |
| import { useAllTrainDiagram } from "@/stateBox/useAllTrainDiagram";
 | |
| 
 | |
| export const EachTrainInfoCore = ({
 | |
|   actionSheetRef,
 | |
|   data,
 | |
|   openStationACFromEachTrainInfo,
 | |
|   from,
 | |
|   navigate,
 | |
| }) => {
 | |
|   const { currentTrain, getCurrentStationData, getPosition } =
 | |
|     useCurrentTrain();
 | |
|   const { originalStationList, stationList } = useStationList();
 | |
|   const { allTrainDiagram: trainList, allCustomTrainData } =
 | |
|     useAllTrainDiagram();
 | |
|   const { setTrainInfo } = useTrainMenu();
 | |
|   const [currentTrainData, setCurrentTrainData] = useState();
 | |
| 
 | |
|   useEffect(() => {
 | |
|     const stationData = getCurrentStationData(data.trainNum);
 | |
|     if (stationData) {
 | |
|       setCurrentTrainData(stationData);
 | |
|     }
 | |
|   }, [currentTrain, data.trainNum]);
 | |
| 
 | |
|   useEffect(() => {
 | |
|     const backAction = () => {
 | |
|       SheetManager.hide("EachTrainInfo");
 | |
|       return true;
 | |
|     };
 | |
|     const backHandler = BackHandler.addEventListener(
 | |
|       "hardwareBackPress",
 | |
|       backAction
 | |
|     );
 | |
|     return () => backHandler.remove();
 | |
|   }, []);
 | |
| 
 | |
|   const [headStation, setHeadStation] = useState([]);
 | |
|   const [tailStation, setTailStation] = useState([]);
 | |
|   const [showHeadStation, setShowHeadStation] = useState([]);
 | |
|   const [showTailStation, setShowTailStation] = useState([]);
 | |
|   const [nearTrainIDList, setNearTrainIDList] = useState([]);
 | |
|   const { getInfluencedTrainData } = useBusAndTrainData();
 | |
|   const [trainPositionSwitch, setTrainPositionSwitch] = useState("false");
 | |
|   const [currentPosition, setCurrentPosition] = useState([]);
 | |
|   const [trainData, setTrainData] = useState([]);
 | |
|   const [trainDataWidhThrough, setTrainDataWithThrough] = useState([]);
 | |
|   const [showThrew, setShowThrew] = useState(false);
 | |
|   const [haveThrough, setHaveThrough] = useState(false);
 | |
| 
 | |
|   // 使用例
 | |
|   const stopStationIDList = trainDataWidhThrough.map((i) => {
 | |
|     const [station, se, time] = i.split(",");
 | |
|     const Stations = stationList.map((a) =>
 | |
|       a.filter((d) => d.StationName == station)
 | |
|     );
 | |
|     const StationNumbers =
 | |
|       Stations &&
 | |
|       Stations.reduce((newArray, e) => {
 | |
|         return newArray.concat(e);
 | |
|       }, []).map((d) => d.StationNumber);
 | |
|     return StationNumbers;
 | |
|   });
 | |
|   useEffect(() => {
 | |
|     const stopStationList = trainData.map((i) => {
 | |
|       const [station, se, time] = i.split(",");
 | |
|       if (se == "通編") setHaveThrough(true);
 | |
|       return stationList.map((a) => a.filter((d) => d.StationName == station));
 | |
|     });
 | |
|     const allThroughStationList = stopStationList.map((i, index, array) => {
 | |
|       let allThroughStation = [];
 | |
|       if (index == array.length - 1) return;
 | |
| 
 | |
|       const firstItem = array[index];
 | |
|       const secondItem = array[index + 1];
 | |
|       let betweenStationLine = "";
 | |
|       let baseStationNumberFirst = "";
 | |
|       let baseStationNumberSecond = "";
 | |
|       Object.keys(stationIDPair).forEach((d, index2, array) => {
 | |
|         if (!d) return;
 | |
|         const haveFirst = firstItem[index2];
 | |
|         const haveSecond = secondItem[index2];
 | |
|         if (haveFirst.length && haveSecond.length) {
 | |
|           betweenStationLine = d;
 | |
|           baseStationNumberFirst = haveFirst[0].StationNumber;
 | |
|           baseStationNumberSecond = haveSecond[0].StationNumber;
 | |
|         }
 | |
|       });
 | |
|       if (!betweenStationLine) return;
 | |
|       let reverse = false;
 | |
|       originalStationList[
 | |
|         lineListPair[stationIDPair[betweenStationLine]]
 | |
|       ].forEach((d) => {
 | |
|         if (
 | |
|           d.StationNumber > baseStationNumberFirst &&
 | |
|           d.StationNumber < baseStationNumberSecond
 | |
|         ) {
 | |
|           allThroughStation.push(`${d.Station_JP},通過,`);
 | |
|           setHaveThrough(true);
 | |
|           reverse = false;
 | |
|         } else {
 | |
|           if (
 | |
|             d.StationNumber < baseStationNumberFirst &&
 | |
|             d.StationNumber > baseStationNumberSecond
 | |
|           ) {
 | |
|             allThroughStation.push(`${d.Station_JP},通過,`);
 | |
|             setHaveThrough(true);
 | |
|             reverse = true;
 | |
|           }
 | |
|         }
 | |
|       });
 | |
|       if (reverse) allThroughStation.reverse();
 | |
|       return allThroughStation;
 | |
|     });
 | |
|     let mainArray = [...trainData];
 | |
|     let indexs = 0;
 | |
|     trainData.forEach((d, index, array) => {
 | |
|       indexs = indexs + 1;
 | |
|       if (!allThroughStationList[index]) return;
 | |
|       if (allThroughStationList[index].length == 0) return;
 | |
|       mainArray.splice(indexs, 0, ...allThroughStationList[index]);
 | |
|       indexs = indexs + allThroughStationList[index].length;
 | |
|     });
 | |
|     setTrainDataWithThrough(mainArray);
 | |
|   }, [trainData]);
 | |
| 
 | |
|   const points =
 | |
|     trainPositionSwitch == "true"
 | |
|       ? findReversalPoints(currentPosition, stopStationIDList)
 | |
|       : stopStationIDList.map(() => false);
 | |
|   const [isJumped, setIsJumped] = useState(false);
 | |
|   useEffect(() => {
 | |
|     if (isJumped) return () => {};
 | |
|     if (!points) return () => {};
 | |
|     if (points.length == 0) return () => {};
 | |
|     const position = points.findIndex((d) => d == true);
 | |
|     let isThrew = false;
 | |
|     if (position == -1) return () => {};
 | |
|     setShowThrew(true);
 | |
|     if (trainDataWidhThrough[position].split(",")[1] == "通過") {
 | |
|       LayoutAnimation.configureNext({
 | |
|         duration: 400,
 | |
|         update: { type: "easeInEaseOut", springDamping: 0.6 },
 | |
|       });
 | |
|       isThrew = true;
 | |
|     }
 | |
|     if (position < 5) {
 | |
|     } // 5駅以内の場合はスクロールしない
 | |
|     else {
 | |
|       const count = position * 44 - 50;
 | |
|       // 0.5秒待機してからスクロール
 | |
|       setTimeout(
 | |
|         () =>
 | |
|           scrollHandlers.ref.current?.scrollTo({ y: count, animated: true }),
 | |
|         400
 | |
|       );
 | |
|     }
 | |
|     setIsJumped(true);
 | |
|   }, [points]);
 | |
|   const { height } = useWindowDimensions();
 | |
|   const { isLandscape } = useDeviceOrientationChange();
 | |
|   const scrollHandlers = actionSheetRef
 | |
|     ? useScrollHandlers("scrollview-1", actionSheetRef)
 | |
|     : null;
 | |
|   const [trueTrainID, setTrueTrainID] = useState([]);
 | |
|   useEffect(() => {
 | |
|     if (!data.trainNum) return;
 | |
|     const TD = trainList[data.trainNum];
 | |
|     setHeadStation([]);
 | |
|     setTailStation([]);
 | |
|     if (!TD) {
 | |
|       const specialTrainActualIDs = searchSpecialTrain(
 | |
|         data.trainNum,
 | |
|         trainList
 | |
|       );
 | |
|       setTrueTrainID(specialTrainActualIDs || []);
 | |
|       setTrainData([]);
 | |
|       return;
 | |
|     }
 | |
|     setTrainData(TD.split("#").filter((d) => d != ""));
 | |
|   }, [data]);
 | |
|   //裏列車探索
 | |
|   useEffect(() => {
 | |
|     if (!data.trainNum) return;
 | |
|     const NearTrainList = getInfluencedTrainData(data.trainNum);
 | |
|     if (NearTrainList.length == 0) return;
 | |
|     const TDArray = NearTrainList.map((d) => d.TrainData);
 | |
|     setNearTrainIDList(NearTrainList.map((d) => d.id));
 | |
|     if (trainData.length == 0) return;
 | |
|     if (TDArray.length == 0) return;
 | |
|     let head = [];
 | |
|     let tail = [];
 | |
|     TDArray.forEach((data, i) =>
 | |
|       data.forEach((d) => {
 | |
|         const [station, se, time] = d.split(",");
 | |
|         if (station == trainData[0].split(",")[0]) {
 | |
|           head.push({
 | |
|             station: trainData[0].split(",")[0],
 | |
|             dia: data,
 | |
|             id: nearTrainIDList[i],
 | |
|           });
 | |
|         }
 | |
|         if (station == trainData[trainData.length - 1].split(",")[0]) {
 | |
|           tail.push({
 | |
|             station: trainData[trainData.length - 1].split(",")[0],
 | |
|             dia: data,
 | |
|             id: nearTrainIDList[i],
 | |
|           });
 | |
|         }
 | |
|       })
 | |
|     );
 | |
|     setHeadStation(head || []);
 | |
|     setTailStation(tail || []);
 | |
|   }, [trainData, data]);
 | |
| 
 | |
|   useEffect(() => {
 | |
|     const position = getPosition(currentTrainData);
 | |
|     if (position) setCurrentPosition(position);
 | |
|   }, [currentTrainData]);
 | |
| 
 | |
|   useEffect(() => {
 | |
|     //列車現在地アイコン表示スイッチ
 | |
|     AS.getItem("trainPositionSwitch")
 | |
|       .then((d) => {
 | |
|         if (d) setTrainPositionSwitch(d);
 | |
|       })
 | |
|       .catch(() => AS.setItem("trainPositionSwitch", "true"));
 | |
|   }, []);
 | |
| 
 | |
|   const openTrainInfo = (d) => {
 | |
|     const train = customTrainDataDetector(d, allCustomTrainData);
 | |
|     let TrainNumber = "";
 | |
|     if (train.trainNumDistance != undefined) {
 | |
|       const timeInfo =
 | |
|         parseInt(d.replace("M", "").replace("D", "")) - train.trainNumDistance;
 | |
|       TrainNumber = timeInfo + "号";
 | |
|     }
 | |
|     const payload = {
 | |
|       data: {
 | |
|         trainNum: d,
 | |
|         limited: `${getTrainType(train.type).data}:${
 | |
|           train.trainName
 | |
|         }${TrainNumber}`,
 | |
|       },
 | |
|       navigate,
 | |
|       from: from == "LED" ? "LED2" : "NearTrainDiagramView",
 | |
|     };
 | |
|     if (isLandscape) {
 | |
|       setTrainInfo(payload.data);
 | |
|     } else {
 | |
|       SheetManager.hide("EachTrainInfo").then(() => {
 | |
|         //0.1秒待機してから開く
 | |
|         setTimeout(() => SheetManager.show("EachTrainInfo", { payload }), 200);
 | |
|       });
 | |
|     }
 | |
|   };
 | |
| 
 | |
|   return (
 | |
|     <View
 | |
|       style={{
 | |
|         backgroundColor: "#0099CC",
 | |
|         borderTopRadius: 5,
 | |
|         borderColor: "dark",
 | |
|         borderWidth: 1,
 | |
|       }}
 | |
|     >
 | |
|       {isLandscape || (
 | |
|         <View style={{ height: 26, width: "100%" }}>
 | |
|           <View
 | |
|             style={{
 | |
|               height: 6,
 | |
|               width: 45,
 | |
|               borderRadius: 100,
 | |
|               backgroundColor: "#f0f0f0",
 | |
|               marginVertical: 10,
 | |
|               alignSelf: "center",
 | |
|             }}
 | |
|           />
 | |
|         </View>
 | |
|       )}
 | |
|       <HeaderText
 | |
|         data={data}
 | |
|         trainData={trainData}
 | |
|         showHeadStation={showHeadStation}
 | |
|         showTailStation={showTailStation}
 | |
|         headStation={headStation}
 | |
|         tailStation={tailStation}
 | |
|         navigate={navigate}
 | |
|         from={from}
 | |
|         scrollHandlers={scrollHandlers}
 | |
|       />
 | |
| 
 | |
|       <DynamicHeaderScrollView
 | |
|         from={from}
 | |
|         styles={styles}
 | |
|         scrollHandlers={scrollHandlers}
 | |
|         containerProps={{
 | |
|           style: {
 | |
|             maxHeight: isLandscape ? height - 94 : (height / 100) * 70,
 | |
|             backgroundColor:
 | |
|               getTrainType(
 | |
|                 customTrainDataDetector(data.trainNum, allCustomTrainData).type
 | |
|               ).data === "notService"
 | |
|                 ? "#777777ff"
 | |
|                 : "white",
 | |
|           },
 | |
|         }}
 | |
|         shortHeader={
 | |
|           <ShortHeader
 | |
|             {...{
 | |
|               currentTrainData,
 | |
|               currentPosition,
 | |
|               nearTrainIDList,
 | |
|               openTrainInfo,
 | |
|               navigate,
 | |
|             }}
 | |
|           />
 | |
|         }
 | |
|         longHeader={
 | |
|           <LongHeader
 | |
|             {...{
 | |
|               currentTrainData,
 | |
|               currentPosition,
 | |
|               nearTrainIDList,
 | |
|               openTrainInfo,
 | |
|               navigate,
 | |
|             }}
 | |
|           />
 | |
|         }
 | |
|         topStickyContent={
 | |
|           <ScrollStickyContent
 | |
|             {...{ currentTrainData, showThrew, setShowThrew, haveThrough }}
 | |
|           />
 | |
|         }
 | |
|       >
 | |
|         {getTrainType(
 | |
|           customTrainDataDetector(data.trainNum, allCustomTrainData).type
 | |
|         ).data === "notService" && (
 | |
|           <Text style={{ backgroundColor: "#ffffffc2", fontWeight: "bold" }}>
 | |
|             この列車には乗車できません。
 | |
|           </Text>
 | |
|         )}
 | |
|         {headStation.length != 0 &&
 | |
|           headStation.map((i, index) =>
 | |
|             showHeadStation.findIndex((d) => d == index) == -1 ? (
 | |
|               <TouchableOpacity
 | |
|                 onPress={() => {
 | |
|                   const array = openBackTrainInfo(i.station, trainData, i.dia);
 | |
|                   if (!array) return;
 | |
|                   setTrainData(array);
 | |
|                   setShowHeadStation([...showHeadStation, index]);
 | |
|                 }}
 | |
|                 style={{
 | |
|                   padding: 10,
 | |
|                   flexDirection: "row",
 | |
|                   borderColor: "blue",
 | |
|                   borderWidth: 1,
 | |
|                   margin: 10,
 | |
|                   borderRadius: 5,
 | |
|                   alignItems: "center",
 | |
|                 }}
 | |
|                 key={i.station + "-head"}
 | |
|               >
 | |
|                 <Text
 | |
|                   style={{ fontSize: 18, fontWeight: "bold", color: "black" }}
 | |
|                 >
 | |
|                   「本当の始発駅」を表示
 | |
|                 </Text>
 | |
|               </TouchableOpacity>
 | |
|             ) : (
 | |
|               <></>
 | |
|             )
 | |
|           )}
 | |
|         <ShowSpecialTrain
 | |
|           isTrainDataNothing={trainData.length == 0}
 | |
|           setTrainData={setTrainData}
 | |
|           trueTrainID={trueTrainID}
 | |
|         />
 | |
|         {!trainData.length && (
 | |
|           <TouchableOpacity
 | |
|             onPress={() =>
 | |
|               Linking.openURL(`https://twitter.com/search?q=${data.trainNum}`)
 | |
|             }
 | |
|             style={{
 | |
|               padding: 10,
 | |
|               flexDirection: "row",
 | |
|               borderColor: "blue",
 | |
|               borderWidth: 1,
 | |
|               margin: 10,
 | |
|               borderRadius: 5,
 | |
|               alignItems: "center",
 | |
|               backgroundColor: "#ffffffc2",
 | |
|             }}
 | |
|           >
 | |
|             <Text style={{ fontSize: 18, fontWeight: "bold", color: "black" }}>
 | |
|               Twitterで検索
 | |
|             </Text>
 | |
|           </TouchableOpacity>
 | |
|         )}
 | |
|         {trainDataWidhThrough.map((i, index) =>
 | |
|           i.split(",")[1] == "提" ? (
 | |
|             <DataFromButton i={i} />
 | |
|           ) : (
 | |
|             <EachStopList
 | |
|               {...{
 | |
|                 i,
 | |
|                 index,
 | |
|                 stationList,
 | |
|                 points: points ? points[index] : false,
 | |
|                 currentTrainData,
 | |
|                 openStationACFromEachTrainInfo,
 | |
|                 showThrew,
 | |
|               }}
 | |
|               key={i + "-stop"}
 | |
|             />
 | |
|           )
 | |
|         )}
 | |
|         <Text style={{ backgroundColor: "#ffffffc2" }}>
 | |
|           時刻が斜体,青色になっている時刻はコミュニティで追加されている独自データです。
 | |
|         </Text>
 | |
|         {tailStation.length != 0 &&
 | |
|           tailStation.map(({ station, dia }, index) =>
 | |
|             showTailStation.findIndex((d) => d == index) == -1 ? (
 | |
|               <TouchableOpacity
 | |
|                 onPress={() => {
 | |
|                   const array = openBackTrainInfo(station, trainData, dia);
 | |
| 
 | |
|                   if (!array) return;
 | |
|                   setTrainData(array);
 | |
| 
 | |
|                   setShowTailStation([...showTailStation, index]);
 | |
|                 }}
 | |
|                 style={{
 | |
|                   padding: 10,
 | |
|                   flexDirection: "row",
 | |
|                   borderColor: "blue",
 | |
|                   borderWidth: 1,
 | |
|                   margin: 10,
 | |
|                   borderRadius: 5,
 | |
|                   alignItems: "center",
 | |
|                 }}
 | |
|               >
 | |
|                 <Text
 | |
|                   style={{ fontSize: 18, fontWeight: "bold", color: "black" }}
 | |
|                 >
 | |
|                   「本当の終着駅」を表示
 | |
|                 </Text>
 | |
|               </TouchableOpacity>
 | |
|             ) : (
 | |
|               <></>
 | |
|             )
 | |
|           )}
 | |
| 
 | |
|         <View style={{ flexDirection: "row" }}>
 | |
|           <View
 | |
|             style={{
 | |
|               padding: 8,
 | |
|               flexDirection: "row",
 | |
|               borderBottomWidth: 1,
 | |
|               borderBottomColor: "#f0f0f0",
 | |
|               backgroundColor: "#ffffffc2",
 | |
|               flex: 1,
 | |
|             }}
 | |
|           >
 | |
|             <Text style={{ fontSize: 20 }}> </Text>
 | |
|             <View style={{ flex: 1 }} />
 | |
|           </View>
 | |
|         </View>
 | |
|       </DynamicHeaderScrollView>
 | |
|     </View>
 | |
|   );
 | |
| };
 | |
| 
 | |
| const styles = StyleSheet.create({
 | |
|   header: {
 | |
|     justifyContent: "center",
 | |
|     alignItems: "center",
 | |
|     left: 0,
 | |
|     right: 0,
 | |
|     //paddingTop: 10,
 | |
|     position: "absolute",
 | |
|     zIndex: 1,
 | |
|     backgroundColor: "f0f0f0",
 | |
|   },
 | |
|   headerText: {
 | |
|     color: "#fff",
 | |
|     fontSize: 25,
 | |
|     fontWeight: "bold",
 | |
|     textAlign: "center",
 | |
|   },
 | |
| });
 |