Files
jrshikoku/components/StationDiagram/ExGridSimpleView.tsx

190 lines
4.9 KiB
TypeScript

import { FC, useRef, useState, useCallback, useEffect, useMemo } from "react";
import {
View,
Text,
ScrollView,
useWindowDimensions,
} from "react-native";
import Animated, {
useAnimatedStyle,
useSharedValue,
} from "react-native-reanimated";
import { useCurrentTrain } from "@/stateBox/useCurrentTrain";
import { useThemeColors } from "@/lib/theme";
import dayjs from "dayjs";
import { ExGridSimpleViewItem } from "./ExGridSimpleViewItem";
type hoge = {
trainNumber: string;
array: string;
name: string;
timeType: string;
time: string;
platformNum: string | null;
}[];
export const ExGridSimpleView: FC<{
data: hoge;
showLastStop: boolean;
}> = ({ data, showLastStop }) => {
const groupKeys = [
"4",
"5",
"6",
"7",
"8",
"9",
"10",
"11",
"12",
"13",
"14",
"15",
"16",
"17",
"18",
"19",
"20",
"21",
"22",
"23",
"0",
"1",
"2",
"3",
];
const { currentTrain } = useCurrentTrain();
const { colors } = useThemeColors();
const groupedData = useMemo(() => {
const initialData: {
[d: number]: {
trainNumber: string;
array: string;
name: string;
timeType: string;
time: string;
isOperating: boolean;
platformNum: string | null;
}[];
} = {
"4": [], "5": [], "6": [], "7": [], "8": [], "9": [],
"10": [], "11": [], "12": [], "13": [], "14": [], "15": [],
"16": [], "17": [], "18": [], "19": [], "20": [], "21": [],
"22": [], "23": [], "0": [], "1": [], "2": [], "3": [],
};
data.forEach((item) => {
let isOperating = false;
let [hour, minute] = dayjs()
.hour(parseInt(item.time.split(":")[0]))
.minute(parseInt(item.time.split(":")[1]))
.format("H:m")
.split(":");
if (currentTrain.findIndex((x) => x.num == item.trainNumber) != -1) {
const currentTrainTime = currentTrain.find(
(x) => x.num == item.trainNumber
)?.delay;
if (currentTrainTime != "入線") {
[hour, minute] = dayjs()
.hour(parseInt(hour))
.minute(parseInt(minute))
.add(currentTrainTime, "minute")
.format("H:m")
.split(":");
}
isOperating = true;
}
initialData[hour].push({ ...item, time: `${hour}:${minute}`, isOperating });
});
return initialData;
}, [data, currentTrain]);
// 時ヘッダーを横にスクロールしたときの処理
const scrollX = useSharedValue(0);
const stickyTextStyle = useAnimatedStyle(() => ({
transform: [{ translateX: scrollX.value }],
}));
const scrollRef = useRef<ScrollView>(null);
const yOffsets = useRef<Record<string, number>>({});
// データが揃ったら次の列車の時間帯へスクロール
useEffect(() => {
if (data.length === 0) return;
const timer = setTimeout(() => {
const now = dayjs();
const nextTrain = data.find((d) => {
const [h, m] = d.time.split(":").map(Number);
const trainTime = h < 4
? dayjs().add(1, "day").hour(h).minute(m)
: dayjs().hour(h).minute(m);
return trainTime.isAfter(now);
});
if (nextTrain) {
const targetHour = String(parseInt(nextTrain.time.split(":")[0]));
const y = yOffsets.current[targetHour];
if (y !== undefined) {
scrollRef.current?.scrollTo({ y: Math.max(0, y - 30), animated: true });
}
}
}, 400);
return () => clearTimeout(timer);
}, [data]);
return (
<ScrollView
ref={scrollRef}
stickyHeaderIndices={
groupKeys.at(0) ? groupKeys.map((_, i) => i * 2) : []
}
style={{ backgroundColor: colors.diagramBackground }}
>
{groupKeys.map((hour) => [
<View
style={{
padding: 5,
borderBottomWidth: 0.5,
borderTopWidth: 0.5,
borderBottomColor: colors.diagramBorder,
backgroundColor: colors.diagramSectionHeader,
}}
onLayout={(e) => { yOffsets.current[hour] = e.nativeEvent.layout.y; }}
key={hour}
>
<Animated.Text
style={[
{
fontSize: 15,
zIndex: 1,
marginLeft: 0,
color: colors.text,
},
stickyTextStyle,
]}
>
{hour}
</Animated.Text>
</View>,
<View
key={hour + "-items"}
style={{
flexDirection: "row",
position: "relative",
flexWrap: "wrap",
}}
>
{groupedData[hour].map((d, i, array) => (
<ExGridSimpleViewItem
key={d.trainNumber + i}
d={d}
index={i}
array={array}
showLastStop={showLastStop}
/>
))}
</View>,
])}
</ScrollView>
);
};