Files
jrshikoku/components/AllTrainDiagramView.tsx
2025-12-12 18:14:40 +00:00

357 lines
11 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import React, { useState, useEffect, FC } from "react";
import {
View,
Text,
TouchableOpacity,
FlatList,
KeyboardAvoidingView,
TextInput,
Platform,
Keyboard,
ScrollView,
Linking,
Image,
} from "react-native";
import { useAllTrainDiagram } from "../stateBox/useAllTrainDiagram";
import { customTrainDataDetector } from "./custom-train-data";
import { getTrainType } from "../lib/getTrainType";
import { SheetManager } from "react-native-actions-sheet";
import { useNavigation } from "@react-navigation/native";
import { BigButton } from "./atom/BigButton";
import { Switch } from "react-native-elements";
import { migrateTrainName } from "@/lib/eachTrainInfoCoreLib/migrateTrainName";
import { OneManText } from "./ActionSheetComponents/EachTrainInfoCore/HeaderTextParts/OneManText";
import { getStringConfig } from "@/lib/getStringConfig";
export const AllTrainDiagramView: FC = () => {
const { goBack, navigate } = useNavigation();
const {
keyList,
allTrainDiagram,
allCustomTrainData,
getTodayOperationByTrainId,
} = useAllTrainDiagram();
const [input, setInput] = useState(""); // 文字入力
const [keyBoardVisible, setKeyBoardVisible] = useState(false);
const [useStationName, setUseStationName] = useState(false);
const [useRegex, setUseRegex] = useState(false);
const regexTextStyle = {
color: "white",
fontSize: 20,
margin: 3,
padding: 3,
};
const regexTextButtonStyle = {
...regexTextStyle,
borderWidth: 1,
borderColor: "white",
borderRadius: 3,
};
useEffect(() => {
const showSubscription = Keyboard.addListener("keyboardDidShow", () => {
setKeyBoardVisible(true);
});
const hideSubscription = Keyboard.addListener("keyboardDidHide", () => {
setKeyBoardVisible(false);
});
return () => {
showSubscription.remove();
hideSubscription.remove();
};
}, []);
const openTrainInfo = (d) => {
const train = customTrainDataDetector(d, allCustomTrainData);
let TrainNumber = "";
if (train.train_num_distance != undefined) {
const timeInfo =
parseInt(d.replace("M", "").replace("D", "")) -
parseInt(train.train_num_distance);
TrainNumber = timeInfo + "号";
}
const type = getTrainType({ type: train.type }).data;
const limited = `${type}:${train.train_name}${TrainNumber}`;
const payload = {
data: { trainNum: d, limited },
navigate,
from: "AllTrainIDList",
};
SheetManager.show("EachTrainInfo", {
payload,
});
};
type ItemProps = {
id: string;
openTrainInfo: (d: string) => void;
};
const Item: FC<ItemProps> = ({ id, openTrainInfo }) => {
const { train_info_img, train_name, type, train_num_distance, to_data } =
customTrainDataDetector(id, allCustomTrainData);
const todayOperation = getTodayOperationByTrainId(id);
const [typeString, fontAvailable, isOneMan] = getStringConfig(type, id);
const trainNameString = (() => {
switch (true) {
case train_name !== "":
// 特急の場合は、列車名を取得
// 列番対称データがある場合はそれから列車番号を取得
const number =
train_num_distance !== "" && !isNaN(parseInt(train_num_distance))
? ` ${parseInt(id) - parseInt(train_num_distance)}`
: "";
return train_name + number;
case allTrainDiagram[id] === undefined:
return "";
case to_data && to_data !== "":
// to_dataがある場合は、to_dataを取得
return migrateTrainName(to_data + "行き");
default:
// 行先がある場合は、行先を取得
const s = allTrainDiagram[id].split("#");
if (!s[s.length - 2]) return "列車情報無し";
const hoge = s[s.length - 2].split(",")[0];
return migrateTrainName(hoge + "行き");
}
})();
return (
<TouchableOpacity
style={{
padding: 5,
flexDirection: "row",
borderColor: "white",
borderWidth: 1,
margin: 5,
borderRadius: 5,
alignItems: "center",
}}
onPress={() => openTrainInfo(id)}
>
<View style={{ marginHorizontal: 5, flexDirection: "row" }}>
{todayOperation.length > 0
? todayOperation.map((operation, index) => (
<Image
key={index}
source={{ uri: operation.vehicle_img }}
style={{
width: 20,
height: 22,
marginHorizontal: 2,
display: index == 0 ? "flex" : "none", //暫定対応:複数アイコンがある場合は最初のアイコンのみ表示
}}
/>
))
: train_info_img && (
<Image
source={{ uri: train_info_img }}
style={{
width: 20,
height: 22,
marginHorizontal: 2,
}}
/>
)}
</View>
{typeString && (
<Text
style={{
fontSize: 20,
color: "white",
fontFamily: fontAvailable ? "JR-Nishi" : undefined,
fontWeight: !fontAvailable ? "bold" : undefined,
marginRight: 5,
}}
>
{typeString}
</Text>
)}
{isOneMan && <OneManText />}
{trainNameString && (
<Text style={{ fontSize: 20, fontWeight: "bold", color: "white" }}>
{trainNameString}
</Text>
)}
<View style={{ flex: 1 }} />
<Text style={{ fontSize: 20, fontWeight: "bold", color: "white" }}>
{id}
</Text>
</TouchableOpacity>
);
};
return (
<View style={{ backgroundColor: "#0099CC", height: "100%" }}>
<FlatList
contentContainerStyle={{ justifyContent: "flex-end", flexGrow: 1 }}
style={{ flex: 1 }}
data={keyList?.filter((d) => {
if (useStationName) {
const EachStopInfo = allTrainDiagram[d].split("#");
const ls = input.split(",").map((inputStationValue) => {
const isHit = EachStopInfo.find((dx) => {
if (!dx) return undefined;
const returnData = dx.split(",")[0] == inputStationValue;
if (returnData) {
const isThrew = dx.split(",")[1].includes("通");
if (isThrew) return undefined;
}
return returnData;
});
return isHit;
});
return !ls.includes(undefined);
}
if (useRegex) {
try {
const regex = new RegExp(input);
return regex.test(d);
} catch (e) {
return false;
}
}
const { train_name, train_number_override } = customTrainDataDetector(
d,
allCustomTrainData
);
return (
d.includes(input) ||
train_name.includes(input) ||
(train_number_override && train_number_override.includes(input))
);
})}
renderItem={({ item }) => <Item {...{ openTrainInfo, id: item }} />}
ListEmptyComponent={
<View style={{ flex: 1, alignItems: "center", marginTop: 50 }}>
<Text style={{ color: "white", fontSize: 20 }}>
</Text>
</View>
}
keyExtractor={(item) => item}
//initialNumToRender={100}
/>
<KeyboardAvoidingView
behavior="padding"
keyboardVerticalOffset={80}
enabled={Platform.OS === "ios"}
>
<View style={{ height: 35, flexDirection: "row" }}>
<Switch
value={useRegex}
onValueChange={() => {
setUseRegex(!useRegex);
setUseStationName(false);
}}
color="red"
style={{ margin: 5 }}
/>
<Text style={{ color: "white", fontSize: 20, margin: 5 }}>
使
</Text>
<Switch
value={useStationName}
onValueChange={() => {
setUseRegex(false);
setUseStationName(!useStationName);
}}
color="red"
style={{ margin: 5 }}
/>
<Text style={{ color: "white", fontSize: 20, margin: 5 }}>
</Text>
</View>
<ScrollView
style={{
height: 35,
flexDirection: "row",
backgroundColor: "#0099CC",
margin: 5,
display: useRegex ? "flex" : "none",
}}
horizontal={true}
>
<Text style={regexTextStyle}></Text>
<Text style={regexTextButtonStyle} onPress={() => setInput("D")}>
</Text>
<Text
style={regexTextButtonStyle}
onPress={() => setInput("3\\d\\d\\dM")}
>
</Text>
<Text
style={regexTextButtonStyle}
onPress={() => setInput("[4,5]\\d\\d\\d[D,M]")}
>
</Text>
<Text
style={regexTextButtonStyle}
onPress={() => setInput("^\\d?\\dM")}
>
</Text>
<Text
style={regexTextButtonStyle}
onPress={() => setInput("^\\d?[0,2,4,6,8]D")}
>
</Text>
<Text
style={regexTextButtonStyle}
onPress={() => setInput("^([\\d])+\\1")}
>
</Text>
<Text
style={{ ...regexTextButtonStyle, backgroundColor: "green" }}
onPress={() =>
Linking.openURL(
"https://qiita.com/tossh/items/635aea9a529b9deb3038"
)
}
>
(Qiita)
</Text>
</ScrollView>
<View
style={{
height: 35,
margin: 5,
alignItems: "center",
backgroundColor: "#F4F4F4",
flexDirection: "row",
paddingLeft: 10,
paddingRight: 10,
borderRadius: 25,
borderColor: "#F4F4F4",
}}
>
<TextInput
placeholder="列番・列車名を入力してフィルタリングします。"
onFocus={() => setKeyBoardVisible(true)}
onEndEditing={() => {}}
onChange={(ret) => setInput(ret.nativeEvent.text)}
value={input}
style={{ flex: 1 }}
/>
</View>
</KeyboardAvoidingView>
<BigButton
onPress={goBack}
string="閉じる"
style={{
display:
Platform.OS === "ios" ? "flex" : keyBoardVisible ? "none" : "flex",
}}
/>
</View>
);
};