Compare commits

...

8 Commits

Author SHA1 Message Date
harukin-expo-dev-env
b620f5cf75 Merge commit '4907186b55d9dee34fa3b07a55b9c99af543b12b' into develop 2024-08-19 14:11:34 +00:00
harukin-expo-dev-env
4907186b55 FooterとHeaderを移動、コードの整理 2024-08-19 14:07:27 +00:00
harukin-expo-dev-env
a4030a8e4c スイッチボックスをコンポーネント分離整理 2024-08-19 13:41:55 +00:00
harukin-expo-dev-env
833d93cf12 style整理 2024-08-19 12:42:07 +00:00
harukin-expo-dev-env
e977bb29f3 小整理 2024-08-19 12:39:55 +00:00
harukin-expo-dev-env
ea6cc8c55a 運行情報の駅別動的表示化 2024-08-19 12:34:12 +00:00
harukin-expo-dev-env
81bb5326f2 当該駅情報を追加、U,Sのバグ修正 2024-08-19 05:03:10 +00:00
harukin-expo-dev-env
019486f665 運行情報バッジに対象路線記号を追加 2024-08-08 13:18:52 +00:00
7 changed files with 502 additions and 176 deletions

4
App.js
View File

@ -60,7 +60,7 @@ export default function App() {
); );
} }
export function AppContainer() { export function AppContainer() {
const { areaInfo } = useAreaInfo(); const { areaInfo, areaIconBadgeText } = useAreaInfo();
const navigationRef = React.useRef(); const navigationRef = React.useRef();
return ( return (
<NavigationContainer name="Root" style={{ flex: 1 }} ref={navigationRef}> <NavigationContainer name="Root" style={{ flex: 1 }} ref={navigationRef}>
@ -98,7 +98,7 @@ export function AppContainer() {
headerTransparent: true, headerTransparent: true,
gestureEnabled: true, gestureEnabled: true,
tabBarIcon: initIcon("train", "Ionicons"), tabBarIcon: initIcon("train", "Ionicons"),
tabBarBadge: areaInfo ? "!" : undefined, tabBarBadge: areaInfo ? areaIconBadgeText : undefined,
}} }}
> >
{(props) => <TNDView {...props} />} {(props) => <TNDView {...props} />}

View File

@ -0,0 +1,38 @@
import { View } from "react-native";
import { SwitchBox } from "./SwitchBox";
export const Footer = (props) => {
const {
trainIDSwitch,
setTrainIDSwitch,
trainDescriptionSwitch,
setTrainDescriptionSwitch,
finalSwitch,
setFinalSwitch,
} = props;
return (
<View style={{ flexDirection: "row", padding: 10, alignItems: "center" }}>
<SwitchBox
value={trainIDSwitch}
setValue={setTrainIDSwitch}
setKey="LEDSettings/trainIDSwitch"
title="種別名 / 列番"
/>
<View style={{ flex: 1 }} />
<SwitchBox
value={trainDescriptionSwitch}
setValue={setTrainDescriptionSwitch}
setKey="LEDSettings/trainDescriptionSwitch"
title="列車情報"
/>
<View style={{ flex: 1 }} />
<SwitchBox
value={finalSwitch}
setValue={setFinalSwitch}
setKey="LEDSettings/finalSwitch"
title="当駅止表示"
/>
</View>
);
};

View File

@ -0,0 +1,48 @@
import { View, Text } from "react-native";
import { useCurrentTrain } from "../../../stateBox/useCurrentTrain";
import LottieView from "lottie-react-native";
import { Ionicons } from "@expo/vector-icons";
export const Header = ({ getCurrentTrain }) => {
const { currentTrainLoading, setCurrentTrainLoading } = useCurrentTrain();
return (
<View
style={{
alignContent: "center",
alignItems: "center",
width: "100%",
marginVertical: 10,
flexDirection: "row",
}}
>
<View style={{ flex: 1 }}></View>
<View style={{}}>
<Text style={{ fontSize: 25, color: "white", fontWeight: "bold" }}>
次の列車
</Text>
<Text style={{ fontSize: 15, color: "white" }}>Next Train</Text>
</View>
<View style={{ flex: 1, flexDirection: "row-reverse" }}>
{currentTrainLoading == "loading" ? (
<LottieView
autoPlay
loop
style={{ width: 40, height: 40, marginRight: 30 }}
source={require("../../../assets/51690-loading-diamonds.json")}
/>
) : currentTrainLoading == "error" ? (
<Ionicons
name="reload"
color="white"
size={30}
style={{ marginRight: 30 }}
onPress={() => {
setCurrentTrainLoading("loading");
getCurrentTrain();
}}
/>
) : null}
</View>
</View>
);
};

View File

@ -0,0 +1,25 @@
import { Text } from "react-native";
import { Switch } from "react-native-elements";
import { AS } from "../../../storageControl";
export const SwitchBox = (props) => {
const { value, setValue, setKey, title } = props;
const textStyle = {
alignItems: "center",
alignContent: "center",
textAlign: "center",
textAlignVertical: "center",
color: "white",
};
return (
<>
<Text style={textStyle}>{title}</Text>
<Switch
value={value}
onValueChange={(v) => {
AS.setItem(setKey, v.toString());
setValue(v);
}}
/>
</>
);
};

View File

@ -1,9 +1,6 @@
import React, { useState, useEffect } from "react"; import React, { useState, useEffect } from "react";
import { View, Text, TouchableOpacity } from "react-native"; import { View, Text, TouchableOpacity } from "react-native";
import { Switch } from "react-native-elements";
import { widthPercentageToDP as wp } from "react-native-responsive-screen"; import { widthPercentageToDP as wp } from "react-native-responsive-screen";
import LottieView from "lottie-react-native";
import { Ionicons } from "@expo/vector-icons";
import { customTrainDataDetector } from "../custom-train-data"; import { customTrainDataDetector } from "../custom-train-data";
import { useInterval } from "../../lib/useInterval"; import { useInterval } from "../../lib/useInterval";
import { objectIsEmpty } from "../../lib/objectIsEmpty"; import { objectIsEmpty } from "../../lib/objectIsEmpty";
@ -14,6 +11,9 @@ import { useCurrentTrain } from "../../stateBox/useCurrentTrain";
import { useAreaInfo } from "../../stateBox/useAreaInfo"; import { useAreaInfo } from "../../stateBox/useAreaInfo";
import { SheetManager } from "react-native-actions-sheet"; import { SheetManager } from "react-native-actions-sheet";
import { AS } from "../../storageControl"; import { AS } from "../../storageControl";
import { Footer } from "./LED_Vision_Component/Footer";
import { Header } from "./LED_Vision_Component/Header";
/** /**
* *
@ -58,30 +58,18 @@ export default function LED_vision(props) {
const [finalSwitch, setFinalSwitch] = useState(false); const [finalSwitch, setFinalSwitch] = useState(false);
const [trainIDSwitch, setTrainIDSwitch] = useState(false); const [trainIDSwitch, setTrainIDSwitch] = useState(false);
const [trainDescriptionSwitch, setTrainDescriptionSwitch] = useState(false); const [trainDescriptionSwitch, setTrainDescriptionSwitch] = useState(false);
const { areaInfo } = useAreaInfo(); const [isInfoArea, setIsInfoArea] = useState(false);
const { areaInfo, areaStationID } = useAreaInfo();
useEffect(() => { useEffect(() => {
AS.getItem("LEDSettings/trainIDSwitch").then((data) => { AS.getItem("LEDSettings/trainIDSwitch").then((data) => {
console.log(data); setTrainIDSwitch(data === "true");
if (data == "true") {
setTrainIDSwitch(true);
} else {
setTrainIDSwitch(false);
}
}); });
AS.getItem("LEDSettings/trainDescriptionSwitch").then((data) => { AS.getItem("LEDSettings/trainDescriptionSwitch").then((data) => {
if (data == "true") { setTrainDescriptionSwitch(data == "true");
setTrainDescriptionSwitch(true);
} else {
setTrainDescriptionSwitch(false);
}
}); });
AS.getItem("LEDSettings/finalSwitch").then((data) => { AS.getItem("LEDSettings/finalSwitch").then((data) => {
if (data == "true") { setFinalSwitch(data == "true");
setFinalSwitch(true);
} else {
setFinalSwitch(false);
}
}); });
}, []); }, []);
@ -93,11 +81,12 @@ export default function LED_vision(props) {
} }
let returnData = {}; let returnData = {};
Object.keys(trainDiagram).forEach((key) => { Object.keys(trainDiagram).forEach((key) => {
if (trainDiagram[key].match(station.Station_JP + ",")) { if (trainDiagram[key].match(station[0].Station_JP + ",")) {
returnData[key] = trainDiagram[key]; returnData[key] = trainDiagram[key];
} }
}); });
setStationDiagram(returnData); setStationDiagram(returnData);
setIsInfoArea(station.some((s) => areaStationID.includes(s.StationNumber)));
}, [trainDiagram, station]); }, [trainDiagram, station]);
const [trainTimeAndNumber, setTrainTimeAndNumber] = useState(null); const [trainTimeAndNumber, setTrainTimeAndNumber] = useState(null);
@ -105,7 +94,7 @@ export default function LED_vision(props) {
useEffect(() => { useEffect(() => {
//現在の駅に停車する列車から時刻を切り出してLEDベースにフォーマット //現在の駅に停車する列車から時刻を切り出してLEDベースにフォーマット
if (objectIsEmpty(stationDiagram)) return () => {}; if (objectIsEmpty(stationDiagram)) return () => {};
const getTimeData = getTime(stationDiagram, station); const getTimeData = getTime(stationDiagram, station[0]);
setTrainTimeAndNumber(getTimeData); setTrainTimeAndNumber(getTimeData);
}, [stationDiagram]); }, [stationDiagram]);
@ -166,11 +155,7 @@ export default function LED_vision(props) {
date.setHours(parseInt(data[0])); date.setHours(parseInt(data[0]));
date.setMinutes(parseInt(data[1]) + parseInt(delay)); date.setMinutes(parseInt(data[1]) + parseInt(delay));
if (!(newDate > date)) { return !(newDate > date);
return true;
}
return false;
}; };
const [areaString, setAreaString] = useState(""); const [areaString, setAreaString] = useState("");
@ -179,11 +164,7 @@ export default function LED_vision(props) {
useInterval( useInterval(
() => { () => {
if (areaInfo != "") { if (areaInfo != "") {
if (areaStringLength < move) { setMove(areaStringLength < move ? 0 : move + 1);
setMove(0);
} else {
setMove(move + 1);
}
} }
}, },
350, 350,
@ -220,17 +201,19 @@ export default function LED_vision(props) {
<Header getCurrentTrain={getCurrentTrain} /> <Header getCurrentTrain={getCurrentTrain} />
{selectedTrain.map((d) => ( {selectedTrain.map((d) => (
<EachData <EachData
d={d} {...{
trainIDSwitch={trainIDSwitch} d,
trainDescriptionSwitch={trainDescriptionSwitch} trainIDSwitch,
station={station} trainDescriptionSwitch,
customTrainDataDetector={customTrainDataDetector} customTrainDataDetector,
navigate={navigate} navigate,
originalStationList={originalStationList} originalStationList,
openStationACFromEachTrainInfo={openStationACFromEachTrainInfo} openStationACFromEachTrainInfo,
}}
station={station[0]}
/> />
))} ))}
{areaString != "" && ( {areaString != "" && isInfoArea && (
<Description <Description
numberOfLines={1} numberOfLines={1}
info={areaString.replaceAll("\n", "").replaceAll("\r", "")} info={areaString.replaceAll("\n", "").replaceAll("\r", "")}
@ -239,120 +222,32 @@ export default function LED_vision(props) {
)} )}
<Footer <Footer
trainIDSwitch={trainIDSwitch} {...{
setTrainIDSwitch={setTrainIDSwitch} trainIDSwitch,
trainDescriptionSwitch={trainDescriptionSwitch} setTrainIDSwitch,
setTrainDescriptionSwitch={setTrainDescriptionSwitch} trainDescriptionSwitch,
finalSwitch={finalSwitch} setTrainDescriptionSwitch,
setFinalSwitch={setFinalSwitch} finalSwitch,
setFinalSwitch,
}}
/> />
</View> </View>
); );
} }
const Header = ({ getCurrentTrain }) => {
const { currentTrainLoading, setCurrentTrainLoading } = useCurrentTrain();
return (
<View
style={{
alignContent: "center",
alignItems: "center",
width: "100%",
marginVertical: 10,
flexDirection: "row",
}}
>
<View style={{ flex: 1 }}></View>
<View style={{}}>
<Text style={{ fontSize: 25, color: "white", fontWeight: "bold" }}>
次の列車
</Text>
<Text style={{ fontSize: 15, color: "white" }}>Next Train</Text>
</View>
<View style={{ flex: 1, flexDirection: "row-reverse" }}>
{currentTrainLoading == "loading" ? (
<LottieView
autoPlay
loop
style={{ width: 40, height: 40, marginRight: 30 }}
source={require("../../assets/51690-loading-diamonds.json")}
/>
) : currentTrainLoading == "error" ? (
<Ionicons
name="reload"
color="white"
size={30}
style={{ marginRight: 30 }}
onPress={() => {
setCurrentTrainLoading("loading");
getCurrentTrain();
}}
/>
) : null}
</View>
</View>
);
};
const Footer = (props) => {
const EachData = (props) => {
const { const {
d,
trainIDSwitch, trainIDSwitch,
setTrainIDSwitch,
trainDescriptionSwitch, trainDescriptionSwitch,
setTrainDescriptionSwitch, station,
finalSwitch, customTrainDataDetector,
setFinalSwitch, navigate,
originalStationList,
openStationACFromEachTrainInfo,
} = props; } = props;
const textStyle = {
alignItems: "center",
alignContent: "center",
textAlign: "center",
textAlignVertical: "center",
color: "white",
};
return (
<View style={{ flexDirection: "row", padding: 10, alignItems: "center" }}>
<Text style={textStyle}>種別名 / 列番</Text>
<Switch
value={trainIDSwitch}
onValueChange={(value) => {
AS.setItem("LEDSettings/trainIDSwitch", value.toString());
setTrainIDSwitch(value);
}}
/>
<View style={{ flex: 1 }} />
<Text style={textStyle}>列車情報</Text>
<Switch
value={trainDescriptionSwitch}
onValueChange={(value) => {
AS.setItem("LEDSettings/trainDescriptionSwitch", value.toString());
setTrainDescriptionSwitch(value);
}}
/>
<View style={{ flex: 1 }} />
<Text style={textStyle}>当駅止表示</Text>
<Switch
value={finalSwitch}
onValueChange={(value) => {
AS.setItem("LEDSettings/finalSwitch", value.toString());
setFinalSwitch(value);
}}
/>
</View>
);
};
const EachData = ({
d,
trainIDSwitch,
trainDescriptionSwitch,
station,
customTrainDataDetector,
navigate,
originalStationList,
openStationACFromEachTrainInfo,
}) => {
const { currentTrain } = useCurrentTrain(); const { currentTrain } = useCurrentTrain();
const openTrainInfo = (d) => { const openTrainInfo = (d) => {
let TrainNumber = ""; let TrainNumber = "";
@ -479,31 +374,21 @@ const LastStation = ({ lastStation }) => {
); );
}; };
const descriptionStyle = {
fontSize: parseInt("16%"),
fontWeight: "bold",
};
const DependTime = ({ time }) => ( const DependTime = ({ time }) => (
<View style={{ flex: 3 }}> <View style={{ flex: 3 }}>
<Text <Text style={{ ...descriptionStyle, color: "white" }}>{time}</Text>
style={{
fontSize: parseInt("16%"),
color: "white",
fontWeight: "bold",
}}
>
{time}
</Text>
</View> </View>
); );
const StatusAndDelay = ({ trainDelayStatus }) => { const StatusAndDelay = ({ trainDelayStatus }) => {
return ( return (
<View style={{ flex: 4 }}> <View style={{ flex: 4 }}>
<Text <Text style={{ ...descriptionStyle, color: "white", paddingLeft: 1 }}>
style={{
fontSize: parseInt("16%"),
color: "white",
fontWeight: "bold",
paddingLeft: 1,
}}
>
{trainDelayStatus} {trainDelayStatus}
</Text> </Text>
</View> </View>
@ -520,20 +405,24 @@ const Description = ({ info, numberOfLines = 0, onClick }) => (
marginHorizontal: "3%", marginHorizontal: "3%",
backgroundColor: "#000", backgroundColor: "#000",
flexDirection: "row", flexDirection: "row",
overflow: "hidden",
}} }}
onPress={onClick} onPress={onClick}
> >
<View style={{ flex: 4 }}> <View style={{ flex: 4, flexDirection: "row" }}>
{numberOfLines == 1 ? (
<Text style={{ ...descriptionStyle, color: "red" }}>
運行情報 &gt;{" "}
</Text>
) : (
<Text style={{ ...descriptionStyle, color: "green" }}> &gt; </Text>
)}
<Text <Text
style={{ style={{ ...descriptionStyle, color: "green" }}
fontSize: parseInt("16%"),
color: "green",
fontWeight: "bold",
}}
numberOfLines={numberOfLines} numberOfLines={numberOfLines}
> >
{" "} {info}
&gt; {info}
</Text> </Text>
</View> </View>
</TouchableOpacity> </TouchableOpacity>

View File

@ -205,7 +205,7 @@ export default function Menu({ getCurrentTrain }) {
allStationData[selectedCurrentStation] && ( allStationData[selectedCurrentStation] && (
<LED_vision <LED_vision
station={ station={
originalStationList && allStationData[selectedCurrentStation][0] originalStationList && allStationData[selectedCurrentStation]
} }
trainDiagram={trainDiagram} trainDiagram={trainDiagram}
getCurrentTrain={getCurrentTrain} getCurrentTrain={getCurrentTrain}

View File

@ -3,6 +3,8 @@ import useInterval from "../lib/useInterval";
const initialState = { const initialState = {
areaInfo: "", areaInfo: "",
setAreainfo: () => {}, setAreainfo: () => {},
areaIconBadgeText: "",
areaStationID: [],
}; };
const AreaInfoContext = createContext(initialState); const AreaInfoContext = createContext(initialState);
@ -10,19 +12,343 @@ const AreaInfoContext = createContext(initialState);
export const useAreaInfo = () => { export const useAreaInfo = () => {
return useContext(AreaInfoContext); return useContext(AreaInfoContext);
}; };
const setoStationID = [
"Y00",
"Y01",
"Y02",
"Y03",
"Y04",
"Y05",
"Y06",
"Y07",
"Y08",
"Y09",
"Y10",
"Y11",
"Y12",
];
const yosan1StationID = [
"Y12",
"Y13",
"Y14",
"Y15",
"Y16",
"Y17",
"Y18",
"Y19",
"Y20",
"Y21",
"Y22",
"Y23",
"Y24",
"Y25",
"Y26",
"Y27",
"Y28",
"Y29",
"Y30",
"Y31",
"Y32",
"Y33",
"Y34",
"Y35",
"Y36",
"Y37",
"Y38",
"Y39",
"Y40",
"Y41",
"Y42",
"Y43",
"Y44",
"Y45",
"Y46",
"Y47",
"Y48",
"Y49",
"Y50",
"Y51",
"Y52",
"Y53",
"Y54",
"Y55",
];
const yosan2StationID = [
"U00",
"U01",
"U02",
"U02-1",
"U03",
"U04",
"U05",
"U06",
"U07",
"U08",
"U09",
"U10",
"U11",
"U12",
"U13",
"U14",
"U15",
"U16",
"U17",
"U18",
"U19",
"U20",
"U21",
"U22",
"U23",
"U24",
"U25",
"U26",
"U27",
"U28",
"S06",
"S07",
"S08",
"S09",
"S10",
"S11",
"S12",
"S13",
"S14",
"S15",
"S16",
"S17",
"S18",
];
const dosan1StationID = [
"D12",
"D13",
"D14",
"D15",
"D16",
"D17",
"D18",
"D19",
"D20",
"D21",
"D22",
"D23",
"D24",
"D25",
"D26",
"D27",
"D28",
"D29",
"D30",
"D31",
"D32",
"D33",
"D34",
"D35",
"D36",
"D37",
"D38",
"D39",
"D40",
"D41",
"D42",
"D43",
"D44",
"D45",
];
const dosan2StationID = [
"K00",
"K01",
"K02",
"K03",
"K04",
"K05",
"K06",
"K07",
"K08",
"K08-1",
"K09",
"K10",
"K11",
"K12",
"K13",
"K14",
"K15",
"K16",
"K17",
"K18",
"K19",
"K20",
"K21",
"K22",
"K23",
"K24",
"K25",
"K26",
];
const kotokuStationID = [
"T00",
"T01",
"T02",
"T03",
"T04",
"T05",
"T06",
"T07",
"T08",
"T09",
"T10",
"T11",
"T12",
"T13",
"T14",
"T15",
"T16",
"T17",
"T18",
"T19",
"T20",
"T21",
"T22",
"T23",
"T24",
"T25",
"T26",
"T27",
"T28",
];
const mugiStationID = [
"M00",
"M01",
"M02",
"M03",
"M04",
"M05",
"M06",
"M07",
"M08",
"M09",
"M10",
"M11",
"M12",
"M13",
"M14",
"M15",
"M16",
"M17",
"M18",
"M19",
"M20",
"M21",
"M22",
"M23",
"M24",
"M25",
"M26",
"M27",
];
const tokushimaStationID = [
"B00",
"B01",
"B02",
"B03",
"B04",
"B05",
"B06",
"B07",
"B08",
"B09",
"B10",
"B11",
"B12",
"B13",
"B14",
"B15",
"B16",
"B17",
"B18",
"B19",
"B20",
"B21",
"B22",
"B23",
"B24",
"B25",
];
const narutoStationID = ["N04", "N05", "N06", "N07", "N08", "N09", "N10"];
const yodoStationID = [
"G27",
"G28",
"G29",
"G30",
"G31",
"G32",
"G33",
"G34",
"G35",
"G36",
"G37",
"G38",
"G39",
"G40",
"G41",
"G42",
"G43",
"G44",
"G45",
"G46",
"G47",
];
const areaStationPair = {
seto: { id: "Y", stationID: setoStationID },
yosan1: { id: "Y", stationID: yosan1StationID },
yosan2: { id: "U,S", stationID: yosan2StationID },
dosan1: { id: "D", stationID: dosan1StationID },
dosan2: { id: "K", stationID: dosan2StationID },
kotoku: { id: "T", stationID: kotokuStationID },
mugi: { id: "M", stationID: mugiStationID },
tokushima: { id: "B", stationID: tokushimaStationID },
naruto: { id: "N", stationID: narutoStationID },
yodo: { id: "G", stationID: yodoStationID },
};
export const AreaInfoProvider = ({ children }) => { export const AreaInfoProvider = ({ children }) => {
const [areaInfo, setAreaInfo] = useState(""); const [areaInfo, setAreaInfo] = useState("");
const getAreaData = () => const [areaIconBadgeText, setAreaIconBadgeText] = useState("");
const [areaStationID, setAreaStationID] = useState([]);
const getAreaData = () => {
fetch( fetch(
"https://script.google.com/macros/s/AKfycbz80LcaEUrhnlEsLkJy0LG2IRO3DBVQhfNmN1d_0f_HvtsujNQpxM90SrV9yKWH_JG1Ww/exec" "https://script.google.com/macros/s/AKfycbz80LcaEUrhnlEsLkJy0LG2IRO3DBVQhfNmN1d_0f_HvtsujNQpxM90SrV9yKWH_JG1Ww/exec"
) )
.then((d) => d.text()) .then((d) => d.text())
.then((d) => setAreaInfo(d)); .then((d) => setAreaInfo(d));
fetch("https://n8n.haruk.in/webhook/jr-shikoku-trainfo-flag")
.then((d) => d.json())
.then((d) => {
if (!d.data) return;
const text = d.data
.filter((e) => e.status)
.map((e) => {
return `${areaStationPair[e.area].id}`;
});
let stationIDList = [];
d.data
.filter((e) => e.status)
.forEach((e) => {
stationIDList = stationIDList.concat(
areaStationPair[e.area].stationID
);
});
setAreaStationID(stationIDList);
setAreaIconBadgeText(text.length == 0 ? "!" : text.join(","));
});
};
useEffect(getAreaData, []); useEffect(getAreaData, []);
useInterval(getAreaData, 60000); //60秒毎に全在線列車取得 useInterval(getAreaData, 60000); //60秒毎に全在線列車取得
return ( return (
<AreaInfoContext.Provider value={{ areaInfo, setAreaInfo }}> <AreaInfoContext.Provider
value={{ areaInfo, setAreaInfo, areaIconBadgeText, areaStationID }}
>
{children} {children}
</AreaInfoContext.Provider> </AreaInfoContext.Provider>
); );