Files
jrshikoku/components/ActionSheetComponents/EachTrainInfoCore.js
2025-12-04 16:06:28 +00:00

323 lines
9.9 KiB
JavaScript

import React, { useEffect, useState } from "react";
import {
View,
Text,
TouchableOpacity,
StyleSheet,
useWindowDimensions,
BackHandler,
Linking,
} from "react-native";
import { SheetManager } from "react-native-actions-sheet";
import { useScrollHandlers } from "react-native-actions-sheet";
import { getTrainType } from "../../lib/getTrainType";
import { customTrainDataDetector } from "../custom-train-data";
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 { ShowSpecialTrain } from "./EachTrainInfo/ShowSpecialTrain";
import { useTrainMenu } from "../../stateBox/useTrainMenu";
import { HeaderText } from "./EachTrainInfoCore/HeaderText";
import { useStationList } from "../../stateBox/useStationList";
import { useAllTrainDiagram } from "@/stateBox/useAllTrainDiagram";
// Custom hooks
import { useTrainDiagramData } from "./EachTrainInfoCore/hooks/useTrainDiagramData";
import { useThroughStations } from "./EachTrainInfoCore/hooks/useThroughStations";
import { useNearbyTrains } from "./EachTrainInfoCore/hooks/useNearbyTrains";
import { useStopStationIDs } from "./EachTrainInfoCore/hooks/useStopStationIDs";
import { useTrainPosition } from "./EachTrainInfoCore/hooks/useTrainPosition";
import { useAutoScroll } from "./EachTrainInfoCore/hooks/useAutoScroll";
import { useExtendedStations } from "./EachTrainInfoCore/hooks/useExtendedStations";
export const EachTrainInfoCore = ({
actionSheetRef,
data,
openStationACFromEachTrainInfo,
from,
navigate,
}) => {
const { stationList } = useStationList();
const { allCustomTrainData } = useAllTrainDiagram();
const { setTrainInfo } = useTrainMenu();
const { height } = useWindowDimensions();
const { isLandscape } = useDeviceOrientationChange();
const scrollHandlers = actionSheetRef
? useScrollHandlers("scrollview-1", actionSheetRef)
: null;
// Custom hooks for data management
const { trainData, setTrainData, trueTrainID } = useTrainDiagramData(data.trainNum);
const { trainDataWithThrough, haveThrough } = useThroughStations(trainData);
const { headStation, tailStation, nearTrainIDList } = useNearbyTrains(data.trainNum, trainData);
const stopStationIDList = useStopStationIDs(trainDataWithThrough);
const { currentTrainData, currentPosition, points, pointsDisplay } = useTrainPosition(
data.trainNum,
stopStationIDList
);
const {
showHeadStation,
showTailStation,
extendToHeadStation,
extendToTailStation,
} = useExtendedStations(trainData, setTrainData);
// UI state
const [showThrew, setShowThrew] = useState(false);
const [isJumped, setIsJumped] = useState(false);
// Auto scroll to current position
useAutoScroll(points, trainDataWithThrough, scrollHandlers, isJumped, setIsJumped, setShowThrew);
// Back button handler
useEffect(() => {
const backAction = () => {
SheetManager.hide("EachTrainInfo");
return true;
};
const backHandler = BackHandler.addEventListener("hardwareBackPress", backAction);
return () => backHandler.remove();
}, []);
const customTrainType = getTrainType({
type: customTrainDataDetector(data.trainNum, allCustomTrainData).type,
});
const openTrainInfo = (trainNum) => {
const train = customTrainDataDetector(trainNum, allCustomTrainData);
let trainNumber = "";
if (train.train_num_distance && !isNaN(train.train_num_distance)) {
const numericPart = parseInt(trainNum.replace("M", "").replace("D", ""));
trainNumber = `${numericPart - train.train_num_distance}`;
}
const limitedData = getTrainType({ type: train.type });
const payload = {
data: {
trainNum,
limited: `${limitedData.data}:${train.train_name}${trainNumber}`,
},
navigate,
from: from === "LED" ? "LED2" : "NearTrainDiagramView",
};
if (isLandscape) {
setTrainInfo(payload.data);
} else {
SheetManager.hide("EachTrainInfo").then(() => {
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:
customTrainType.data === "notService" ? "#777777ff" : "white",
},
}}
shortHeader={
<ShortHeader
{...{
currentTrainData,
currentPosition,
nearTrainIDList,
openTrainInfo,
navigate,
}}
/>
}
longHeader={
<LongHeader
{...{
currentTrainData,
currentPosition,
nearTrainIDList,
openTrainInfo,
navigate,
}}
/>
}
topStickyContent={
<ScrollStickyContent
{...{ currentTrainData, showThrew, setShowThrew, haveThrough }}
/>
}
>
{customTrainType.data === "notService" && (
<Text style={{ backgroundColor: "#ffffffc2", fontWeight: "bold" }}>
この列車には乗車できません
</Text>
)}
{headStation.length > 0 &&
headStation.map((item, index) =>
!showHeadStation.includes(index) && (
<TouchableOpacity
onPress={() => extendToHeadStation(item.station, item.dia, index)}
style={styles.extendStationButton}
key={`${item.station}-head`}
>
<Text style={styles.extendStationText}>
本当の始発駅を表示
</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={styles.twitterSearchButton}
>
<Text style={styles.extendStationText}>
Twitterで検索
</Text>
</TouchableOpacity>
)}
{trainDataWithThrough.map((item, index, array) =>
item.split(",")[1] === "提" ? (
<DataFromButton i={item} key={`${item}-data`} />
) : (
<EachStopList
i={item}
index={index}
stationList={stationList}
points={pointsDisplay?.[index] || false}
currentTrainData={currentTrainData}
openStationACFromEachTrainInfo={openStationACFromEachTrainInfo}
showThrew={showThrew}
array={array}
key={`${item}-stop`}
/>
)
)}
<Text style={styles.customDataNote}>
時刻が斜体,青色になっている時刻はコミュニティで追加されている独自データです
</Text>
{tailStation.length > 0 &&
tailStation.map(({ station, dia }, index) =>
!showTailStation.includes(index) && (
<TouchableOpacity
onPress={() => extendToTailStation(station, dia, index)}
style={styles.extendStationButton}
key={`${station}-tail`}
>
<Text style={styles.extendStationText}>
本当の終着駅を表示
</Text>
</TouchableOpacity>
)
)}
<View style={styles.bottomSpacer} />
</DynamicHeaderScrollView>
</View>
);
};
const styles = StyleSheet.create({
header: {
justifyContent: "center",
alignItems: "center",
left: 0,
right: 0,
position: "absolute",
zIndex: 1,
backgroundColor: "f0f0f0",
},
headerText: {
color: "#fff",
fontSize: 25,
fontWeight: "bold",
textAlign: "center",
},
extendStationButton: {
padding: 10,
flexDirection: "row",
borderColor: "blue",
borderWidth: 1,
margin: 10,
borderRadius: 5,
alignItems: "center",
},
extendStationText: {
fontSize: 18,
fontWeight: "bold",
color: "black",
},
twitterSearchButton: {
padding: 10,
flexDirection: "row",
borderColor: "blue",
borderWidth: 1,
margin: 10,
borderRadius: 5,
alignItems: "center",
backgroundColor: "#ffffffc2",
},
customDataNote: {
backgroundColor: "#ffffffc2",
},
bottomSpacer: {
flexDirection: "row",
padding: 8,
borderBottomWidth: 1,
borderBottomColor: "#f0f0f0",
backgroundColor: "#ffffffc2",
flex: 1,
},
});