350 lines
10 KiB
TypeScript
350 lines
10 KiB
TypeScript
import React, { FC, useMemo } from "react";
|
|
import { Text, View, TextStyle, TouchableOpacity } from "react-native";
|
|
import { SheetManager } from "react-native-actions-sheet";
|
|
import { migrateTrainName } from "../../../lib/eachTrainInfoCoreLib/migrateTrainName";
|
|
import { TrainIconStatus } from "./trainIconStatus";
|
|
import { OneManText } from "./HeaderTextParts/OneManText";
|
|
import { customTrainDataDetector } from "@/components/custom-train-data";
|
|
import { InfogramText } from "@/components/ActionSheetComponents/EachTrainInfoCore/HeaderTextParts/InfogramText";
|
|
import { useTrainMenu } from "@/stateBox/useTrainMenu";
|
|
import { useAllTrainDiagram } from "@/stateBox/useAllTrainDiagram";
|
|
import { useNotification } from "@/stateBox/useNotifications";
|
|
import { getStringConfig } from "@/lib/getStringConfig";
|
|
import { MaterialCommunityIcons } from "@expo/vector-icons";
|
|
import { getPDFViewURL } from "@/lib/getPdfViewURL";
|
|
import type { NavigateFunction } from "@/types";
|
|
import { useUnyohub } from "@/stateBox/useUnyohub";
|
|
import { useElesite } from "@/stateBox/useElesite";
|
|
import { useThemeColors } from "@/lib/theme";
|
|
import { formatWrappedTrainType, shouldWrapTrainType } from "@/lib/trainTypeWrap";
|
|
import { useResponsive } from "@/lib/responsive";
|
|
import { normalizeIconDisplayMode } from "@/lib/iconDisplayMode";
|
|
|
|
type Props = {
|
|
data: { trainNum: string; limited: string };
|
|
trainData: string[];
|
|
showHeadStation: number[];
|
|
showTailStation: number[];
|
|
headStation: { id: string }[];
|
|
tailStation: { id: string }[];
|
|
navigate: NavigateFunction;
|
|
from: string;
|
|
fontLoaded: boolean;
|
|
scrollRef: any;
|
|
};
|
|
|
|
const textConfig: TextStyle = {
|
|
fontSize: 17,
|
|
fontWeight: "bold",
|
|
};
|
|
|
|
export const HeaderText: FC<Props> = ({
|
|
data,
|
|
trainData,
|
|
showHeadStation,
|
|
showTailStation,
|
|
headStation,
|
|
tailStation,
|
|
navigate,
|
|
from,
|
|
scrollRef,
|
|
}) => {
|
|
const { trainNum } = data;
|
|
|
|
const { fixed } = useThemeColors();
|
|
const { fontScale } = useResponsive();
|
|
const { iconSetting } = useTrainMenu();
|
|
const { allCustomTrainData, getTodayOperationByTrainId } =
|
|
useAllTrainDiagram();
|
|
const { expoPushToken } = useNotification();
|
|
const {
|
|
getUnyohubByTrainNumber,
|
|
getUnyohubEntriesByTrainNumber,
|
|
useUnyohub: unyohubEnabled,
|
|
unyohubData,
|
|
} = useUnyohub();
|
|
const { getElesiteEntriesByTrainNumber, useElesite: elesiteEnabled } =
|
|
useElesite();
|
|
const iconDisplayMode = normalizeIconDisplayMode(iconSetting);
|
|
|
|
const additionalSources = {
|
|
unyohub: unyohubEnabled,
|
|
elesite: elesiteEnabled,
|
|
};
|
|
const hasAdditionalSources = Object.values(additionalSources).some(Boolean);
|
|
|
|
const [
|
|
typeName,
|
|
trainName,
|
|
fontFamily,
|
|
isOneMan,
|
|
infogram,
|
|
priority,
|
|
uwasa,
|
|
trainInfoUrl,
|
|
directions,
|
|
customTrainData,
|
|
] = useMemo(() => {
|
|
const result = customTrainDataDetector(trainNum, allCustomTrainData);
|
|
const {
|
|
type,
|
|
train_name,
|
|
train_num_distance,
|
|
infogram,
|
|
priority,
|
|
uwasa,
|
|
train_info_url,
|
|
to_data,
|
|
directions,
|
|
} = result;
|
|
const [typeString, fontFamily, isOneMan] = getStringConfig(
|
|
type,
|
|
trainNum,
|
|
);
|
|
switch (true) {
|
|
case train_name !== "":
|
|
return [
|
|
typeString,
|
|
train_name +
|
|
(train_num_distance !== "" && !isNaN(parseInt(train_num_distance))
|
|
? ` ${parseInt(trainNum) - parseInt(train_num_distance)}号`
|
|
: ""),
|
|
fontFamily,
|
|
isOneMan,
|
|
infogram,
|
|
priority,
|
|
uwasa,
|
|
train_info_url,
|
|
directions,
|
|
result,
|
|
];
|
|
case trainData[trainData.length - 1] === undefined:
|
|
return [
|
|
typeString,
|
|
"",
|
|
fontFamily,
|
|
isOneMan,
|
|
infogram,
|
|
priority,
|
|
uwasa,
|
|
train_info_url,
|
|
directions,
|
|
result,
|
|
];
|
|
case to_data && to_data !== "":
|
|
return [
|
|
typeString,
|
|
`${to_data}行き`,
|
|
fontFamily,
|
|
isOneMan,
|
|
infogram,
|
|
priority,
|
|
uwasa,
|
|
train_info_url,
|
|
directions,
|
|
result,
|
|
];
|
|
default:
|
|
return [
|
|
typeString,
|
|
migrateTrainName(
|
|
`${trainData[trainData.length - 1].split(",")[0]}行き`,
|
|
),
|
|
fontFamily,
|
|
isOneMan,
|
|
infogram,
|
|
priority,
|
|
uwasa,
|
|
train_info_url,
|
|
directions,
|
|
result,
|
|
];
|
|
}
|
|
}, [trainData, trainNum, allCustomTrainData]);
|
|
|
|
const allTodayOperation = getTodayOperationByTrainId(trainNum) ?? [];
|
|
const todayOperation = allTodayOperation.filter((d) => d.state !== 100);
|
|
|
|
let iconTrainDirection =
|
|
parseInt(trainNum.replace(/[^\d]/g, "")) % 2 == 0 ? true : false;
|
|
if (directions != undefined) {
|
|
iconTrainDirection = directions ? true : false;
|
|
}
|
|
|
|
const unyohubLookupNum = customTrainData?.train_number_override || trainNum;
|
|
const isFreightRetsuban = unyohubLookupNum.includes("レ");
|
|
const unyohubTrainNumForSourceScreen = isFreightRetsuban
|
|
? unyohubLookupNum.replace(/レ/g, "")
|
|
: unyohubLookupNum;
|
|
const freightUnyohubCandidates = (() => {
|
|
const digits = unyohubTrainNumForSourceScreen.replace(/[^\d]/g, "");
|
|
const candidates = new Set<string>();
|
|
if (!digits) return candidates;
|
|
candidates.add(digits);
|
|
if (/^\d{2}$/.test(digits)) {
|
|
candidates.add(`30${digits}`);
|
|
candidates.add(`90${digits}`);
|
|
} else if (/^(30|90)\d{2}$/.test(digits)) {
|
|
candidates.add(digits.slice(-2));
|
|
}
|
|
return candidates;
|
|
})();
|
|
const unyohubFormation = getUnyohubByTrainNumber(unyohubLookupNum);
|
|
const unyohubEntries = isFreightRetsuban
|
|
? unyohubData.filter((unyo) =>
|
|
unyo.trains?.some(
|
|
(t) => !!t.train_number && freightUnyohubCandidates.has(t.train_number),
|
|
),
|
|
)
|
|
: getUnyohubEntriesByTrainNumber(unyohubTrainNumForSourceScreen);
|
|
const elesiteEntries = getElesiteEntriesByTrainNumber(trainNum);
|
|
|
|
const hasUnyohubFormation = unyohubEntries.some(
|
|
(e) => !!e.formations && e.formations.trim() !== "",
|
|
);
|
|
const hasElesiteFormation = elesiteEntries.some(
|
|
(e) => (e.formation_config?.units?.length ?? 0) > 0,
|
|
);
|
|
|
|
const hasExtraInfo =
|
|
priority > 200 ||
|
|
todayOperation.length > 0 ||
|
|
hasUnyohubFormation ||
|
|
hasElesiteFormation;
|
|
|
|
const wrapType = shouldWrapTrainType(typeName, trainName);
|
|
|
|
const openTrainInfoUrl = () => {
|
|
if (!trainInfoUrl) return;
|
|
const uri = trainInfoUrl.includes("pdf")
|
|
? getPDFViewURL(trainInfoUrl)
|
|
: trainInfoUrl;
|
|
navigate("generalWebView", { uri, useExitButton: true });
|
|
SheetManager.hide("EachTrainInfo");
|
|
};
|
|
|
|
return (
|
|
<View
|
|
style={{
|
|
padding: 10,
|
|
flexDirection: "row",
|
|
alignItems: "center",
|
|
width: "100%",
|
|
}}
|
|
onTouchStart={() =>
|
|
scrollRef.current?.scrollTo({ y: 0, animated: true })
|
|
}
|
|
>
|
|
<TrainIconStatus
|
|
data={data}
|
|
navigate={navigate}
|
|
from={from}
|
|
todayOperation={todayOperation}
|
|
direction={iconTrainDirection}
|
|
iconDisplayMode={iconDisplayMode}
|
|
/>
|
|
|
|
<View
|
|
style={{
|
|
flexDirection: "row",
|
|
alignItems: "center",
|
|
marginBottom: 2,
|
|
}}
|
|
>
|
|
<Text
|
|
numberOfLines={wrapType ? 2 : 1}
|
|
style={{
|
|
fontSize: fontScale(20),
|
|
color: fixed.textOnPrimary,
|
|
fontFamily,
|
|
fontWeight: fontFamily ? undefined : "bold",
|
|
marginRight: 5,
|
|
flexShrink: 0,
|
|
...(wrapType
|
|
? { width: fontScale(44), lineHeight: fontScale(22) }
|
|
: {}),
|
|
}}
|
|
>
|
|
{wrapType ? formatWrappedTrainType(typeName) : typeName}
|
|
{fontFamily === "JR-WEST-PLUS" ? (
|
|
<Text style={{ fontFamily: "DiaPro", fontSize: 7 }}>{"\u00A0"}</Text>
|
|
) : null}
|
|
</Text>
|
|
{isOneMan && <OneManText />}
|
|
</View>
|
|
<TouchableOpacity
|
|
style={{
|
|
borderRadius: 5,
|
|
flexDirection: "row",
|
|
alignItems: "center",
|
|
flexShrink: 1,
|
|
flexWrap: "wrap",
|
|
...(trainInfoUrl
|
|
? {
|
|
borderWidth: 0,
|
|
borderBottomWidth: 1,
|
|
borderStyle: "solid",
|
|
borderColor: fixed.textOnPrimary,
|
|
}
|
|
: {}),
|
|
}}
|
|
onPress={openTrainInfoUrl}
|
|
disabled={!trainInfoUrl}
|
|
>
|
|
<Text
|
|
style={{
|
|
...textConfig,
|
|
color: fixed.textOnPrimary,
|
|
...(trainName.length > 10
|
|
? { fontSize: fontScale(16) }
|
|
: { fontSize: fontScale(17) }),
|
|
flexShrink: 1,
|
|
}}
|
|
>
|
|
{trainName}
|
|
</Text>
|
|
<InfogramText infogram={infogram} />
|
|
</TouchableOpacity>
|
|
<View style={{ flex: 1 }} />
|
|
<Text style={{ ...textConfig, fontSize: fontScale(17), color: fixed.textOnPrimary }}>
|
|
{showHeadStation.map((d) => `${headStation[d].id} + `)}
|
|
{trainNum}
|
|
{showTailStation.map((d) => ` + ${tailStation[d].id}`)}
|
|
</Text>
|
|
<MaterialCommunityIcons
|
|
name="database"
|
|
color={hasExtraInfo ? "yellow" : fixed.textOnPrimary}
|
|
size={30}
|
|
style={{ margin: 5 }}
|
|
onPress={() => {
|
|
if (hasAdditionalSources) {
|
|
(SheetManager.show as any)("TrainDataSources", {
|
|
payload: {
|
|
trainNum,
|
|
unyohubTrainNum: unyohubTrainNumForSourceScreen,
|
|
unyohubEntries,
|
|
elesiteEntries,
|
|
todayOperation,
|
|
navigate,
|
|
expoPushToken,
|
|
priority,
|
|
direction: iconTrainDirection,
|
|
customTrainData,
|
|
typeName,
|
|
trainName,
|
|
departureStation: trainData[0]?.split(",")[0] ?? "",
|
|
destinationStation:
|
|
trainData[trainData.length - 1]?.split(",")[0] ?? "",
|
|
},
|
|
});
|
|
} else {
|
|
const uri = `https://jr-shikoku-data-system.pages.dev/trainData/${trainNum}?userID=${expoPushToken}&from=eachTrainInfo`;
|
|
navigate("generalWebView", { uri, useExitButton: false });
|
|
SheetManager.hide("EachTrainInfo");
|
|
}
|
|
}}
|
|
/>
|
|
</View>
|
|
);
|
|
};
|