diff --git a/App.js b/App.js index 028e4cf..2eb95e5 100644 --- a/App.js +++ b/App.js @@ -20,6 +20,8 @@ import Setting from "./components/settings.js"; import TrainMenu from "./components/trainMenu.js"; import FavoriteList from "./components/FavoriteList.js"; import { LogBox } from "react-native"; +import useInterval from "./lib/useInterval"; +import { HeaderConfig } from "./lib/HeaderConfig"; LogBox.ignoreLogs([ "ViewPropTypes will be removed", @@ -65,6 +67,30 @@ export default function App() { }); }, []); + const [currentTrain, setCurrentTrain] = useState([]); //現在在線中の全列車 { num: 列車番号, delay: 遅延時分(状態), Pos: 位置情報 } + const [currentTrainLoading, setCurrentTrainLoading] = useState("loading"); // success, error, loading + const getCurrentTrain = () => + fetch( + "https://train.jr-shikoku.co.jp/g?arg1=train&arg2=train", + HeaderConfig + ) + .then((response) => response.json()) + .then((d) => + d.map((x) => ({ num: x.TrainNum, delay: x.delay, Pos: x.Pos })) + ) + .then((d) => { + setCurrentTrain(d); + setCurrentTrainLoading("success"); + }) + .catch((e) => { + console.log("えらー"); + setCurrentTrainLoading("error"); + }); + + useEffect(getCurrentTrain, []); //初回だけ現在の全在線列車取得 + + useInterval(getCurrentTrain, 15000); //15秒毎に全在線列車取得 + return ( @@ -83,6 +109,12 @@ export default function App() { favoriteStation={favoriteStation} setFavoriteStation={setFavoriteStation} busAndTrainData={busAndTrainData} + currentTrainState={{ currentTrain, setCurrentTrain }} + currentTrainLoadingState={{ + currentTrainLoading, + setCurrentTrainLoading, + }} + getCurrentTrain={getCurrentTrain} /> )} @@ -101,6 +133,12 @@ export default function App() { favoriteStation={favoriteStation} setFavoriteStation={setFavoriteStation} busAndTrainData={busAndTrainData} + currentTrainState={{ currentTrain, setCurrentTrain }} + currentTrainLoadingState={{ + currentTrainLoading, + setCurrentTrainLoading, + }} + getCurrentTrain={getCurrentTrain} /> )} @@ -142,6 +180,9 @@ const Top = ({ favoriteStation, setFavoriteStation, busAndTrainData, + currentTrainState, + currentTrainLoadingState, + getCurrentTrain, }) => { const webview = useRef(); @@ -178,6 +219,9 @@ const Top = ({ setFavoriteStation={setFavoriteStation} busAndTrainData={busAndTrainData} stationData={mapsStationData} + currentTrainState={currentTrainState} + currentTrainLoadingState={currentTrainLoadingState} + getCurrentTrain={getCurrentTrain} /> )} @@ -194,7 +238,6 @@ const Top = ({ @@ -234,6 +277,9 @@ function MenuPage({ favoriteStation, setFavoriteStation, busAndTrainData, + currentTrainState, + currentTrainLoadingState, + getCurrentTrain, }) { useEffect(() => { const unsubscribe = navigation.addListener("tabPress", (e) => { @@ -265,6 +311,9 @@ function MenuPage({ favoriteStation={favoriteStation} setFavoriteStation={setFavoriteStation} busAndTrainData={busAndTrainData} + currentTrainState={currentTrainState} + currentTrainLoadingState={currentTrainLoadingState} + getCurrentTrain={getCurrentTrain} /> )} @@ -284,6 +333,14 @@ function MenuPage({ > {(props) => } + + {(props) => } + ); } diff --git a/Apps.js b/Apps.js index fc05805..031d11c 100644 --- a/Apps.js +++ b/Apps.js @@ -15,6 +15,8 @@ import { getStationList, lineList } from "./lib/getStationList"; import { StationDeteilView } from "./components/ActionSheetComponents/StationDeteilView"; import { injectJavascriptData } from "./lib/webViewInjectjavascript"; import { getStationList2 } from "./lib/getStationList2"; +import { EachTrainInfo } from "./components/ActionSheetComponents/EachTrainInfo"; +import { checkDuplicateTrainData } from "./lib/checkDuplicateTrainData"; /* import StatusbarDetect from './StatusbarDetect'; var Status = StatusbarDetect(); */ @@ -26,7 +28,13 @@ export default function Apps({ setFavoriteStation, busAndTrainData, stationData, + currentTrainState, + currentTrainLoadingState, + getCurrentTrain, }) { + const { currentTrain, setCurrentTrain } = currentTrainState; + const { currentTrainLoading, setCurrentTrainLoading } = + currentTrainLoadingState; const { navigate } = navigation; var urlcache = ""; @@ -35,11 +43,20 @@ export default function Apps({ const [mapSwitch, setMapSwitch] = useState(undefined); const [stationMenu, setStationMenu] = useState(undefined); + //列車情報表示関連 + const EachTrainInfoAsSR = useRef(null); + const [trainInfo, setTrainInfo] = useState({ + trainNum: undefined, + limited: undefined, + trainData: undefined, + }); + //駅情報画面用 const StationBoardAcSR = useRef(null); const [stationBoardData, setStationBoardData] = useState(undefined); const [originalStationList, setOriginalStationList] = useState(); const [selectedStation, setSelectedStation] = useState(undefined); + const [trainMenu, setTrainMenu] = useState("true"); let once = false; useEffect(() => { getStationList().then(setOriginalStationList); @@ -50,7 +67,8 @@ export default function Apps({ const injectJavascript = injectJavascriptData( mapSwitch, iconSetting, - stationMenu + stationMenu, + trainMenu ); useEffect(() => { @@ -102,9 +120,23 @@ export default function Apps({ AS.setItem("stationSwitch", "true").then(Updates.reloadAsync) ); }, []); + useEffect(() => { + //列車メニュースイッチ + AS.getItem("trainSwitch") + .then((d) => { + if (d) { + setTrainMenu(d); + } else { + AS.setItem("trainSwitch", "true").then(Updates.reloadAsync); + } + }) + .catch((d) => + AS.setItem("trainSwitch", "true").then(Updates.reloadAsync) + ); + }, []); const onMessage = (event) => { - if (!event.nativeEvent.data.includes("PopUpMenu")) { + if (event.nativeEvent.data.includes("train.html")) { navigate("trainbase", { info: event.nativeEvent.data, from: "Train" }); return; } @@ -112,34 +144,50 @@ export default function Apps({ alert("駅名標データを取得中..."); return; } - const selectedStationPDFAddress = event.nativeEvent.data - .split(",")[3] - .replace("'", "") - .replace("'", ""); + const dataSet = JSON.parse(event.nativeEvent.data); + switch (dataSet.type) { + case "PopUpMenu": { + const selectedStationPDFAddress = dataSet.pdf; + const findStationEachLine = (selectLine) => { + let NearStation = selectLine.filter( + (d) => d.StationTimeTable == selectedStationPDFAddress + ); + return NearStation; + }; + let returnDataBase = lineList + .map((d) => findStationEachLine(originalStationList[d])) + .filter((d) => d.length > 0) + .reduce((pre, current) => { + pre.push(...current); + return pre; + }, []); - const findStationEachLine = (selectLine) => { - let NearStation = selectLine.filter( - (d) => d.StationTimeTable == selectedStationPDFAddress - ); - 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) { - setStationBoardData(returnDataBase); - StationBoardAcSR.current?.setModalVisible(); - } else { - setStationBoardData(undefined); - StationBoardAcSR.current?.hide(); + if (returnDataBase.length) { + setStationBoardData(returnDataBase); + StationBoardAcSR.current?.show(); + } else { + setStationBoardData(undefined); + StationBoardAcSR.current?.hide(); + } + return; + } + case "ShowTrainTimeInfo": { + const { trainNum, limited } = dataSet; + //alert(trainNum, limited); + setTrainInfo({ + trainNum, + limited, + trainData: checkDuplicateTrainData( + currentTrain.filter((a) => a.num == trainNum) + ), + }); //遅延情報は未実装 + EachTrainInfoAsSR.current?.show(); + return; + } + default: { + return; + } } - - return; }; const onNavigationStateChange = (event) => { @@ -148,7 +196,7 @@ export default function Apps({ urlcache = event.url; if (event.url.includes("https://train.jr-shikoku.co.jp/usage.htm")) { - if (Platform.OS === "android") navigate("howto"); + if (Platform.OS === "android") navigate("howto", { info: event.url }); webview?.current.goBack(); //Actions.howto(); } else if ( @@ -161,7 +209,48 @@ export default function Apps({ } } }; + function sleep(waitSec, callbackFunc) { + // 経過時間(秒) + var spanedSec = 0; + // 1秒間隔で無名関数を実行 + var id = setInterval(function () { + spanedSec++; + + // 経過時間 >= 待機時間の場合、待機終了。 + if (spanedSec >= waitSec) { + // タイマー停止 + clearInterval(id); + + // 完了時、コールバック関数を実行 + if (callbackFunc) callbackFunc(); + } + }, 1); + } + + const openStationACFromEachTrainInfo = (stationName) => { + EachTrainInfoAsSR.current?.hide(); + 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) { + setStationBoardData(returnDataBase); + sleep(25, function () { + StationBoardAcSR.current?.show(); + }); + } else { + setStationBoardData(undefined); + StationBoardAcSR.current?.hide(); + } + }; return ( { + StationBoardAcSR.current?.setModalVisible(); + navigate("Apps"); + }} + /> + ); diff --git a/app.json b/app.json index d5792ae..1aaf982 100644 --- a/app.json +++ b/app.json @@ -22,7 +22,7 @@ "**/*" ], "ios": { - "buildNumber": "27", + "buildNumber": "28", "supportsTablet": true, "bundleIdentifier": "jrshikokuinfo.xprocess.hrkn", "config": { diff --git a/assets/A.png b/assets/A.png new file mode 100644 index 0000000..c7ec559 Binary files /dev/null and b/assets/A.png differ diff --git a/assets/B.png b/assets/B.png new file mode 100644 index 0000000..1bfe39f Binary files /dev/null and b/assets/B.png differ diff --git a/assets/雑.png b/assets/雑.png new file mode 100644 index 0000000..c103c17 Binary files /dev/null and b/assets/雑.png differ diff --git a/components/ActionSheetComponents/EachTrainInfo.js b/components/ActionSheetComponents/EachTrainInfo.js new file mode 100644 index 0000000..8471af1 --- /dev/null +++ b/components/ActionSheetComponents/EachTrainInfo.js @@ -0,0 +1,713 @@ +import React, { useEffect, useState } from "react"; +import { + View, + LayoutAnimation, + ScrollView, + Linking, + Text, + TouchableOpacity, + TouchableWithoutFeedback, + TouchableHighlight, + Platform, +} from "react-native"; +import { Ionicons, MaterialCommunityIcons } from "@expo/vector-icons"; +import ActionSheet from "react-native-actions-sheet"; +import { AS } from "../../storageControl"; +import LottieView from "lottie-react-native"; +import trainList from "../../assets/originData/trainList"; +import { lineList } from "../../lib/getStationList"; +import { + heightPercentageToDP, + widthPercentageToDP, +} from "react-native-responsive-screen"; +import lineColorList from "../../assets/originData/lineColorList"; + +export const EachTrainInfo = ({ + setRef, + data, + navigate, + originalStationList, + openStationACFromEachTrainInfo, + from, +}) => { + const [trainData, setTrainData] = useState([]); + const [isTop, setIsTop] = useState(true); + const [currentPosition, setCurrentPosition] = useState([]); + + const [trainPositionSwitch, setTrainPositionSwitch] = useState("false"); + + useEffect(() => { + //列車現在地アイコン表示スイッチ + AS.getItem("trainPositionSwitch") + .then((d) => { + if (d) { + setTrainPositionSwitch(d); + } else { + } + }) + .catch((d) => AS.setItem("trainPositionSwitch", "false")); + }, []); + + const getStationData = (stationName) => { + const Stations = stationList.map((a) => + a.filter((d) => d.StationName == stationName) + ); + const Station = + Stations && + Stations.reduce((newArray, e) => { + return newArray.concat(e); + }, []); + if (!Station[0]) return []; + return Station.map((d) => d.StationNumber)[0]; + }; + useEffect(() => { + //data.trainData.Pos = "鴨川~端岡"; //test + if (!data.trainData?.Pos) return; + if (data.trainData?.Pos.match("~")) { + const pos = data.trainData?.Pos.replace("(下り)", "") + .replace("(上り)", "") + .split("~"); + setCurrentPosition([getStationData(pos[0]), getStationData(pos[1])]); + } else { + setCurrentPosition([getStationData(data.trainData?.Pos)]); + } + }, [data.trainData]); + + const stationList = + originalStationList && + lineList.map((d) => + originalStationList[d].map((a) => ({ + StationNumber: a.StationNumber, + StationName: a.Station_JP, + })) + ); + const stopStationIDList = trainData.map((i, index) => { + 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); + }, []) + .filter((d) => d.StationNumber) + .map((d) => d.StationNumber); + return StationNumbers[0]; + }); + function findReversalPoints(array) { + // arrayは現在位置の駅ID(駅在宅の場合は1つの配列、駅間の場合は2つの配列) + // stopStationIDListは停車駅の駅IDの配列 + if (!stopStationIDList.length) return []; + const arrayNumber = array.map((d) => ({ + line: d + .split("") + .filter((s) => "A" < s && s < "Z") + .join(""), + ID: d + .split("") + .filter((s) => "0" <= s && s <= "9") + .join(""), + })); + const stopStationIDListNumber = stopStationIDList.map((d) => { + if (!d) return { line: [], ID: [] }; + return { + line: d + .split("") + .filter((s) => "A" < s && s < "Z") + .join(""), + ID: d + .split("") + .filter((s) => "0" <= s && s <= "9") + .join(""), + }; + }); + // 完全一致 + if (array.length == 1) { + const index = stopStationIDList.indexOf(array[0]); + if (index != -1) return [index]; + // 通過駅の場合 + for (let i = 0; i < stopStationIDListNumber.length - 1; i++) { + if (stopStationIDListNumber[i].ID < arrayNumber[0].ID) { + if (stopStationIDListNumber[i + 1].ID > arrayNumber[0].ID) { + return [i + 1]; + } + } + if (stopStationIDListNumber[i].ID > arrayNumber[0].ID) { + if (stopStationIDListNumber[i + 1].ID < arrayNumber[0].ID) { + return [i + 1]; + } + } + } + } + // 駅間の場合 + if (array.length == 2) { + const index1 = stopStationIDList.indexOf(array[0]); + const index2 = stopStationIDList.indexOf(array[1]); + if (index1 != -1 && index2 != -1) { + // 駅間で通過駅も無い場合 + if (index1 < index2) { + if (index1 + 1 == index2) { + return [index2]; + } else { + const returnArray = []; + for (let i = index1 + 1; i <= index2; i++) { + returnArray.push(i); + } + return returnArray; + } + } + if (index1 > index2) { + if (index2 + 1 == index1) return [index1]; + else { + const returnArray = []; + for (let i = index2 + 1; i <= index1; i++) { + returnArray.push(i); + } + return returnArray; + } + } + } else { + const getNearStationID = (stationID) => { + for (let i = 0; i <= stopStationIDListNumber.length; i++) { + if (stopStationIDListNumber[i].ID < stationID) { + if (stopStationIDListNumber[i + 1].ID > stationID) { + return i + 1; + } + } + if (stopStationIDListNumber[i].ID > stationID) { + if (stopStationIDListNumber[i + 1].ID < stationID) { + return i + 1; + } + } + } + }; + let newIndex1 = index1; + let newIndex2 = index2; + if (index1 == -1) { + newIndex1 = getNearStationID(arrayNumber[0].ID); + } + if (index2 == -1) { + newIndex2 = getNearStationID(arrayNumber[1].ID); + } + if (newIndex1 && newIndex2) { + return [newIndex1, newIndex2]; + } + + // 通過駅の場合 + } + + return []; + } + } + // 使用例 + const points = + trainPositionSwitch == "true" ? findReversalPoints(currentPosition) : []; + + useEffect(() => { + setIsTop(true); + if (!data.trainNum) return; + const TD = trainList[data.trainNum]; + if (!TD) { + setTrainData([]); + return; + } + setTrainData(TD.split("#").filter((d) => d != "")); + }, [data]); + const getType = (string) => { + switch (string) { + case "express": + return "特急"; + case "rapid": + return "快速"; + default: + return ""; + } + }; + + const migrateTrainName = (string) => { + return string + .replace("マリン", "マリンライナー") + .replace("ライナーライナー", "ライナー"); + }; + + return ( + } + > + + + + + + + {data.limited + ? getType(data.limited.split(":")[0]) + + migrateTrainName( + data.limited.split(":")[1] || + (trainData.length > 0 + ? trainData[trainData.length - 1].split(",")[0] + "行き" + : " ") + ) + : ""} + + + + {data.trainNum} + + {data.limited != undefined && + getType(data.limited.split(":")[0]) && + !data.limited.split(":")[1].match("サンポート") && ( + { + LayoutAnimation.easeInEaseOut(); //setLoadingDelayData(true); + + navigate("trainbase", { + info: "train.html?tn=" + data.trainNum, + from, + }); + setRef.current?.hide(); + }} + /> + )} + + + + + + 現在地 {currentPosition.toString()} + + + {data.trainData?.Pos && data.trainData?.Pos.match("~") ? ( + <> + + { + data.trainData?.Pos.replace("(下り)", "") + .replace("(上り)", "") + .split("~")[0] + } + + + ~ + + + { + data.trainData?.Pos.replace("(下り)", "") + .replace("(上り)", "") + .split("~")[1] + } + + + ) : ( + + {data.trainData?.Pos} + + )} + + + + + {isNaN(data.trainData?.delay) ? "状態" : "遅延時分"} + + + + {data.trainData?.delay} + {isNaN(data.trainData?.delay) ? "" : "分"} + + + + 列番 + + {data.trainData?.num} + + + + + {/* + + + 行先 + + + 岡山 + + + + + 車両案内 + + + 宇多津でうずしお号と連結 + + + + + + + 編成(使用車両:2700系) + + + + {"[<自][自>][アン自|指>][アン指|G>]"} + + + + */} + + { + if (!Platform.OS !== "android") return; + setIsTop(e.nativeEvent.contentOffset.y < 0); + }} + > + + + {/* + ほげほげふがふが */} + + + 停車駅 + + + {!isNaN(data.trainData?.delay) && + data.trainData?.delay != 0 && ( + + (定刻) + + )} + + 見込 + + + + + + {trainData.map((i, index) => { + 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); + }, []) + .filter((d) => d.StationNumber) + .map((d) => d.StationNumber); + + const colorIDs = + StationNumbers != null + ? StationNumbers.map((d) => { + return d.split("").filter((s) => "A" < s && s < "Z"); + }).reduce((newArray, e) => { + return newArray.concat(e); + }, []) + : []; + const EachIDs = + StationNumbers != null + ? StationNumbers.map((d) => { + return d + .split("") + .filter((s) => "0" <= s && s <= "9") + .join(""); + }) + : []; + const date = new Date(); + if (time) { + date.setHours(time.split(":")[0], time.split(":")[1]); + } + if (!isNaN(data.trainData?.delay)) { + date.setMinutes(date.getMinutes() + data.trainData?.delay); + } + const timeString = date.toTimeString().split(" ")[0].split(":"); + return ( + openStationACFromEachTrainInfo(station)} + key={station} + > + + + {colorIDs.map((color, index) => ( + + + + {colorIDs[index]} + + + {EachIDs[index]} + + + + ))} + + + {station} + + {points.findIndex((d) => d == index) >= 0 ? ( + + 🚊 + + ) : null} + {!isNaN(data.trainData?.delay) && + data.trainData?.delay != 0 && ( + + {time} + + )} + + {timeString[0]}:{timeString[1]} + + + {se?.replace("発", "出発").replace("着", "到着")} + + + + + ); + })} + + + + + + ); +}; diff --git a/components/ActionSheetComponents/StationDeteilView.js b/components/ActionSheetComponents/StationDeteilView.js index f3d11c3..78c3625 100644 --- a/components/ActionSheetComponents/StationDeteilView.js +++ b/components/ActionSheetComponents/StationDeteilView.js @@ -20,6 +20,7 @@ import { heightPercentageToDP as hp, } from "react-native-responsive-screen"; import lineColorList from "../../assets/originData/lineColorList"; +import { getPDFViewURL } from "../../lib/getPdfViewURL"; export const StationDeteilView = (props) => { const { @@ -29,6 +30,8 @@ export const StationDeteilView = (props) => { favoriteStation, setFavoriteStation, busAndTrainData, + navigate, + onExit, } = props; const [trainBus, setTrainBus] = useState(); useEffect(() => { @@ -41,7 +44,11 @@ export const StationDeteilView = (props) => { } setTrainBus(data[0]); }, [currentStation]); - + const info = + currentStation && + (currentStation[0].StationTimeTable.match(".pdf") + ? getPDFViewURL(currentStation[0].StationTimeTable) + : currentStation[0].StationTimeTable); return ( { originalStationList={originalStationList} favoriteStation={favoriteStation} setFavoriteStation={setFavoriteStation} - oP={() => Linking.openURL(currentStation[0].StationTimeTable)} + oP={() => { + navigate("howto", { + info, + onExit, + }); + StationBoardAcSR.current?.hide(); + }} + oLP={() => Linking.openURL(currentStation[0].StationTimeTable)} /> )} @@ -99,6 +113,21 @@ export const StationDeteilView = (props) => { currentStation[0].JrHpUrl && currentStation[0].StationNumber != "M12" && ( <駅構内図 //高松/阿波池田&後免&須崎kounai.png児島例外/ + oP={() => { + navigate("howto", { + info: + currentStation[0].JrHpUrl.replace("/index.html", "/") + + "/kounai_map.html", + onExit, + }); + StationBoardAcSR.current?.hide(); + }} + oLP={() => { + Linking.openURL( + currentStation[0].JrHpUrl.replace("/index.html", "/") + + "/kounai_map.html" + ); + }} uri={currentStation[0].JrHpUrl.replace("/index.html", "/")} /> )} @@ -109,7 +138,14 @@ export const StationDeteilView = (props) => { backgroundColor={"#AD7FA8"} icon={} flex={1} - onPressButton={() => + onPressButton={() => { + navigate("howto", { + info: currentStation[0].JrHpUrl, + onExit, + }); + StationBoardAcSR.current?.hide(); + }} + onLongPressButton={() => Linking.openURL(currentStation[0].JrHpUrl) } > @@ -121,7 +157,14 @@ export const StationDeteilView = (props) => { backgroundColor={"#8F5902"} icon={} flex={1} - onPressButton={() => + onPressButton={() => { + navigate("howto", { + info, + onExit, + }); + StationBoardAcSR.current?.hide(); + }} + onLongPressButton={() => Linking.openURL(currentStation[0].StationTimeTable) } > @@ -145,7 +188,14 @@ export const StationDeteilView = (props) => { backgroundColor={"#CE5C00"} icon={} flex={1} - onPressButton={() => Linking.openURL(trainBus.address)} + onPressButton={() => { + navigate("howto", { + info: trainBus.address, + onExit, + }); + StationBoardAcSR.current?.hide(); + }} + onLongPressButton={() => Linking.openURL(trainBus.address)} > 並行バス @@ -312,7 +362,8 @@ const 駅構内図 = (props) => { alignItems: "center", margin: 2, }} - onPress={() => Linking.openURL(props.uri + "/kounai_map.html")} + onPress={props.oP} + onLongPress={props.oLP} //onPress={() => setOpen(!open)} > diff --git a/components/atom/TicketBox.js b/components/atom/TicketBox.js index 6d34b95..8fc3a33 100644 --- a/components/atom/TicketBox.js +++ b/components/atom/TicketBox.js @@ -1,7 +1,14 @@ import { TouchableOpacity, Text } from "react-native"; export const TicketBox = (props) => { - const { icon, backgroundColor, flex, onPressButton, children } = props; + const { + icon, + backgroundColor, + flex, + onPressButton, + children, + onLongPressButton, + } = props; return ( { alignItems: "center", }} onPress={onPressButton} + onLongPress={onLongPressButton} > {children} diff --git a/components/custom-train-data.js b/components/custom-train-data.js index 3a52d4b..78f1234 100644 --- a/components/custom-train-data.js +++ b/components/custom-train-data.js @@ -619,3 +619,37 @@ export const customTrainDataDetector = (TrainNumber) => { break; } }; +export const getJRF = (num) => { + switch (num) { + case "71": + return "東京(タ)→高松(タ)\\n"; + case "73": + case "75": + return "大阪(タ)→高松(タ)\\n"; + case "3079": + return "高松(タ)→伊予三島\\n"; + case "3071": + case "3077": + return "高松(タ)→新居浜\\n"; + case "3073": + return "高松(タ)→松山貨物\\n"; + case "70": + return "高松(タ)→東京(タ)\\n"; + case "74": + case "76": + return "高松(タ)→大阪(タ)\\n"; + case "3078": + return "伊予三島→高松(タ)\\n"; + case "3070": + return "新居浜→高松(タ)\\n"; + case "3076": + return "新居浜→高松(タ)\\n"; + case "3072": + return "松山貨物→高松(タ)\\n"; + case "9070": + return "臨時貨物\\n"; + default: + JRF = true; + return null; + } +}; diff --git a/components/settings.js b/components/settings.js index 529d501..f2372f5 100644 --- a/components/settings.js +++ b/components/settings.js @@ -13,10 +13,14 @@ export default function Setting(props) { const [iconSetting, setIconSetting] = useState(undefined); const [mapSwitch, setMapSwitch] = useState(undefined); const [stationMenu, setStationMenu] = useState(undefined); + const [trainMenu, setTrainMenu] = useState(undefined); + const [trainPosition, setTrainPosition] = useState(undefined); useEffect(() => { AS.getItem("iconSwitch").then(setIconSetting); AS.getItem("mapSwitch").then(setMapSwitch); AS.getItem("stationSwitch").then(setStationMenu); + AS.getItem("trainSwitch").then(setTrainMenu); + AS.getItem("trainPositionSwitch").then(setTrainPosition); }, []); return ( @@ -83,7 +87,7 @@ export default function Setting(props) { textAlignVertical: "center", }} > - 駅メニューを表示(beta) + 駅メニューを表示 - 内部バージョン: 4.5.3 + 列車メニュー + + + setTrainMenu(value.toString())} + /> + + + + →列車現在位置表示(alpha) + + + setTrainPosition(value.toString())} + /> + + + + 列車メニュー + + + setTrainMenu(value.toString())} + /> + + + + →列車現在位置表示(alpha) + + + setTrainPosition(value.toString())} + /> + + + + 内部バージョン: 4.5.4 @@ -137,6 +217,8 @@ export default function Setting(props) { AS.setItem("iconSwitch", iconSetting.toString()), AS.setItem("mapSwitch", mapSwitch.toString()), AS.setItem("stationSwitch", stationMenu.toString()), + AS.setItem("trainSwitch", trainMenu.toString()), + AS.setItem("trainPositionSwitch", trainPosition.toString()), ]).then(() => { Updates.reloadAsync(); }); diff --git a/components/trainMenu.js b/components/trainMenu.js index ed6af21..3069e1d 100644 --- a/components/trainMenu.js +++ b/components/trainMenu.js @@ -58,7 +58,11 @@ export default function TrainMenu({ backgroundColor={"#F89038"} icon="train-car" flex={1} - onPressButton={() => navigate("howto")} + onPressButton={() => + navigate("howto", { + info: "https://train.jr-shikoku.co.jp/usage.htm", + }) + } > 使い方 diff --git a/components/発車時刻表/LED_vidion.js b/components/発車時刻表/LED_vidion.js index af069ef..91c586c 100644 --- a/components/発車時刻表/LED_vidion.js +++ b/components/発車時刻表/LED_vidion.js @@ -6,8 +6,11 @@ import LottieView from "lottie-react-native"; import { Ionicons, MaterialCommunityIcons } from "@expo/vector-icons"; import { customTrainDataDetector } from "../custom-train-data"; import { useInterval } from "../../lib/useInterval"; -import trainList from "../../assets/originData/trainList"; import { objectIsEmpty } from "../../lib/objectIsEmpty"; +import { getTrainType } from "../../lib/getTrainType"; +import { HeaderConfig } from "../../lib/HeaderConfig"; +import { getTrainDelayStatus } from "../../lib/getTrainDelayStatus"; +import { checkDuplicateTrainData } from "../../lib/checkDuplicateTrainData"; let diagramData = undefined; @@ -41,48 +44,23 @@ let diagramData = undefined; * 9062D 四国まんなか千年ものがたり(臨時?) */ export default function LED_vision(props) { - const HeaderConfig = { - headers: { - referer: "https://train.jr-shikoku.co.jp/sp.html", - }, - }; - const [trainDiagram, setTrainDiagram] = useState(null); // 全列車のダイヤを列番ベースで整理 + const { + station, + setTrainInfo, + EachTrainInfoAsSR, + trainDiagram, + currentTrainState, + currentTrainLoadingState, + getCurrentTrain, + } = props; + const { currentTrain, setCurrentTrain } = currentTrainState; + const { currentTrainLoading, setCurrentTrainLoading } = + currentTrainLoadingState; const [stationDiagram, setStationDiagram] = useState({}); //当該駅の全時刻表 - const [currentTrain, setCurrentTrain] = useState(null); //現在在線中の全列車 - const [currentTrainLoading, setCurrentTrainLoading] = useState("loading"); const [finalSwitch, setFinalSwitch] = useState(false); const [trainIDSwitch, setTrainIDSwitch] = useState(false); const [trainDescriptionSwitch, setTrainDescriptionSwitch] = useState(false); - const parseAllTrainDiagram = (text) => { - const val = text.replace("[\r\n", "").split(",\r\n"); - let trainDiagram = {}; - val.forEach((element) => { - try { - let data = JSON.parse(element); - Object.keys(data).forEach((key) => (trainDiagram[key] = data[key])); - } catch (e) {} - }); - return trainDiagram; - }; - - useEffect(() => { - //全列車リストを生成する副作用[無条件初回実行] - fetch( - "https://train.jr-shikoku.co.jp/g?arg1=station&arg2=traintimeinfo&arg3=dia", - HeaderConfig - ) - .then((response) => response.text()) - .then((d) => { - if (d.indexOf("404 Not Found") != -1) throw Error; - setTrainDiagram(parseAllTrainDiagram(d)); - }) - .catch((d) => { - console.log("fallback"); - setTrainDiagram(trainList); - }); - }, []); - useEffect(() => { // 現在の駅に停車するダイヤを作成する副作用[列車ダイヤと現在駅情報] if (!trainDiagram) { @@ -91,52 +69,54 @@ export default function LED_vision(props) { } let returnData = {}; Object.keys(trainDiagram).forEach((key) => { - if (trainDiagram[key].match(props.station.Station_JP + ",")) { + if (trainDiagram[key].match(station.Station_JP + ",")) { returnData[key] = trainDiagram[key]; } }); setStationDiagram(returnData); - }, [trainDiagram, props.station]); + }, [trainDiagram, station]); - const getCurrentTrain = () => - fetch( - "https://train.jr-shikoku.co.jp/g?arg1=train&arg2=train", - HeaderConfig - ) - .then((response) => response.json()) - .then((d) => - d.map((x) => ({ num: x.TrainNum, delay: x.delay, Pos: x.Pos })) - ) - .then((d) => { - setCurrentTrain(d); - setCurrentTrainLoading("success"); - }) - .catch((e) => { - console.log("えらー"); - setCurrentTrainLoading("error"); - }); + const [trainTimeAndNumber, setTrainTimeAndNumber] = useState(null); - useEffect(getCurrentTrain, []); //初回だけ現在の全在線列車取得 + useEffect(() => { + //現在の駅に停車する列車から時刻を切り出してLEDベースにフォーマット + if (objectIsEmpty(stationDiagram)) return () => {}; + const getTimeData = getTime(stationDiagram, station); + setTrainTimeAndNumber(getTimeData); + }, [stationDiagram]); - useInterval(getCurrentTrain, 15000); //15秒毎に全在線列車取得 + 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((d) => { - let a = {}; - stationDiagram[d].split("#").forEach((data) => { + const returnData = Object.keys(stationDiagram).map((trainNum) => { + let trainData = {}; + stationDiagram[trainNum].split("#").forEach((data) => { if (data.match("着")) { - a.lastStation = data.split(",着,")[0]; + trainData.lastStation = data.split(",着,")[0]; } if (data.split(",")[0] === station.Station_JP) { if (data.match(",発,")) { - a.time = data.split(",発,")[1]; + trainData.time = data.split(",発,")[1]; } else { - a.time = data.split(",着,")[1]; - a.lastStation = "当駅止"; + trainData.time = data.split(",着,")[1]; + trainData.lastStation = "当駅止"; } } }); - return { train: d, time: a.time, lastStation: a.lastStation }; + return { + train: trainNum, + time: trainData.time, + lastStation: trainData.lastStation, + }; }); return returnData.sort((a, b) => { switch (true) { @@ -152,15 +132,6 @@ export default function LED_vision(props) { }); }; - const [trainTimeAndNumber, setTrainTimeAndNumber] = useState(null); - - useEffect(() => { - //現在の駅に停車する列車から時刻を切り出してLEDベースにフォーマット - if (objectIsEmpty(stationDiagram)) return () => {}; - const getTimeData = getTime(stationDiagram, props.station); - setTrainTimeAndNumber(getTimeData); - }, [stationDiagram]); - const timeFiltering = (d) => { const date = new Date(); const newDate = new Date(); @@ -178,16 +149,6 @@ export default function LED_vision(props) { return false; }; - 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]); return ( ))}