190 lines
4.9 KiB
TypeScript
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>
|
|
);
|
|
};
|