diff --git a/MenuPage.js b/MenuPage.js index 5102368..4e7647e 100644 --- a/MenuPage.js +++ b/MenuPage.js @@ -19,6 +19,7 @@ import { useNavigation } from "@react-navigation/native"; import { news } from "./config/newsUpdate"; import { useBottomTabBarHeight } from "@react-navigation/bottom-tabs"; import GeneralWebView from "./GeneralWebView"; +import { StationDiagramView } from "@/components/StationDiagram/StationDiagramView"; const Stack = createStackNavigator(); export function MenuPage() { @@ -86,7 +87,7 @@ export function MenuPage() { }) .catch((error) => { if (__DEV__) { - console.warn('お気に入り駅の読み込みに失敗しました:', error); + console.warn("お気に入り駅の読み込みに失敗しました:", error); } }); }); @@ -112,6 +113,11 @@ export function MenuPage() { /> )} /> + - + ); } diff --git a/Top.js b/Top.js index 5f25b74..2925744 100644 --- a/Top.js +++ b/Top.js @@ -14,6 +14,7 @@ import { AS } from "./storageControl"; import { news } from "./config/newsUpdate"; import { Linking, Platform } from "react-native"; import GeneralWebView from "./GeneralWebView"; +import { StationDiagramView } from "@/components/StationDiagram/StationDiagramView"; const Stack = createStackNavigator(); export const Top = () => { const { webview } = useCurrentTrain(); @@ -37,7 +38,8 @@ export const Top = () => { return; } if (!isFocused()) navigate("positions", { screen: "Apps" }); - else if (mapSwitch == "true") navigate("positions", { screen: "trainMenu" }); + else if (mapSwitch == "true") + navigate("positions", { screen: "trainMenu" }); else webview.current?.injectJavaScript(`AccordionClassEvent()`); return; }; @@ -64,8 +66,17 @@ export const Top = () => { options={{ ...optionData }} component={TrainBase} /> + - + { if (!props.payload) return <>; @@ -132,6 +133,11 @@ export const StationDeteilView = (props) => { onExit={onExit} /> )} + {!currentStation[0].StationTimeTable || ( void; + onExit: () => void; + currentStation: { + Station_JP: string; + Station_EN: string; + StationName?: string; + MyStation?: string; + StationNumber: string; + DispNum?: string; + StationTimeTable: string; + StationMap?: string; + JrHpUrl?: string; + lat: number; + lng: number; + jslodApi: string; + }[]; +}; +export const StationDiagramButton: FC = (props) => { + const { navigate, onExit, currentStation } = props; + return ( + } + flex={1} + onPressButton={() => { + navigate("stDiagram", { + currentStation, + }); + onExit(); + }} + > + 時刻表v2 + + ); +}; diff --git a/components/StationDiagram/ExGridView.tsx b/components/StationDiagram/ExGridView.tsx new file mode 100644 index 0000000..9b3e230 --- /dev/null +++ b/components/StationDiagram/ExGridView.tsx @@ -0,0 +1,355 @@ +import { FC, useRef, useState, useCallback, useEffect } from "react"; +import { + View, + Text, + ScrollView, + useWindowDimensions, + Vibration, +} from "react-native"; +import { ExGridViewItem } from "./ExGridViewItem"; +import Animated, { + useAnimatedStyle, + useSharedValue, + runOnJS, + useAnimatedScrollHandler, + withTiming, + Easing, + FadeIn, + FadeOut, + BounceInUp, + FadeInUp, + FadeOutUp, +} from "react-native-reanimated"; +import { Gesture, GestureDetector } from "react-native-gesture-handler"; +import { ExGridViewTimePositionItem } from "./ExGridViewTimePositionItem"; +import { useCurrentTrain } from "@/stateBox/useCurrentTrain"; +import dayjs from "dayjs"; +type hoge = { + trainNumber: string; + array: string; + name: string; + timeType: string; + time: string; +}[]; +export const ExGridView: FC<{ + data: hoge; +}> = ({ data }) => { + const groupedData: { + [d: number]: { + trainNumber: string; + array: string; + name: string; + timeType: string; + time: string; + isOperating: boolean; + }[]; + } = { + "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 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 { width } = useWindowDimensions(); + const { currentTrain } = useCurrentTrain(); + 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(parseInt(currentTrainTime), "minute") + .format("H:m") + .split(":"); + } + isOperating = true; + } + groupedData[hour].push({ ...item, time: `${hour}:${minute}`, isOperating }); + }); + // ドラッグ位置を保持する共有値 + const widthX = useSharedValue(width); + const savedWidthX = useSharedValue(width); + const isChanging = useSharedValue(false); + const [scrollEnabled, setScrollEnabled] = useState(true); + const scrollRef = useRef(null); + const scrollRef2 = useRef(null); + + // ScrollViewの有効/無効を切り替える関数 + const toggleScrollEnabled = useCallback((enabled: boolean) => { + setScrollEnabled(enabled); + }, []); + + // パンジェスチャー(ドラッグ)のハンドラー + const pinchGesture = Gesture.Pinch() + .onUpdate((e) => { + const calc = savedWidthX.value * e.scale; + widthX.value = calc > width ? calc : width; + //runOnJS(scrollToRightEnd)(); + }) + .onEnd(() => { + savedWidthX.value = widthX.value; + }); + + const gesture = Gesture.Pan() + .minPointers(2) // 最低2本指 + .maxPointers(2) // 最大2本指 + .onStart(() => { + runOnJS(toggleScrollEnabled)(false); + }) + .onEnd(() => { + runOnJS(toggleScrollEnabled)(true); + savedWidthX.value = widthX.value; + }); + const longPressGesture = Gesture.Pan() + .minPointers(1) + .maxPointers(1) + .activateAfterLongPress(200) + .onStart(() => { + runOnJS(Vibration.vibrate)(30); + isChanging.value = true; + }) + .onUpdate((e) => { + const calc = widthX.value + e.velocityY; + widthX.value = calc > width ? calc : width; + }) + .onEnd(() => { + console.log("Long press ended"); + isChanging.value = false; + }); + + // ジェスチャーを組み合わせる + const composed = Gesture.Simultaneous( + longPressGesture, + pinchGesture, + gesture + ); + + // アニメーションスタイル + const animatedStyle = useAnimatedStyle(() => ({ + width: widthX.value, + backgroundColor: isChanging.value ? "#8adeffff" : "white", + })); + // 時ヘッダーを横にスクロールしたときの処理 + const scrollX = useSharedValue(0); + const scrollHandler = useAnimatedScrollHandler({ + onScroll: (event) => { + scrollX.value = event.contentOffset.x; + }, + }); + const stickyTextStyle = useAnimatedStyle(() => ({ + transform: [{ translateX: scrollX.value }], + })); + const animatedLongPressStyle = useAnimatedStyle(() => ({ + display: isChanging.value ? "flex" : "none", + })); + useEffect(() => { + const getCurrentTime = dayjs().hour(); + setTimeout(() => { + const keyTime = + getCurrentTime - 4 <= 0 ? getCurrentTime + 24 : getCurrentTime; + const goTo = keyTime * 60; + if (goTo > 400) { + scrollRef2.current?.scrollTo({ y: goTo - 300, animated: true }); + } + }, 400); + }, [scrollRef2]); + return ( + <> + + + ↑縮小 ・ 拡大↓ + + + + { + // 現在のスクロール位置を取得 + const currentScrollX = scrollX.value; + const containerWidth = width - 50; + + // コンテンツが画面からはみ出している場合のみ右端にスクロール + if (currentScrollX + containerWidth > contentWidth) { + const newScrollX = Math.max(0, contentWidth - containerWidth); + scrollRef.current?.scrollTo({ x: newScrollX, animated: true }); + } + }} + ref={scrollRef} + contentContainerStyle={{ + flexDirection: "column", + backgroundColor: "white", + }} + > + + {Array.from({ length: 60 }, (_, i) => i + 1).map((num) => { + if (num % 5 === 0) { + return ( + + {num - 5} + + ); + } else return <>; + })} + + (分) + + + i * 2) : [] + } + ref={scrollRef2} + > + {groupKeys.map((hour) => [ + + + {hour}時台 + + , + + {groupedData[hour].map((d, i, array) => ( + + ))} + + , + ])} + + + + + ); +}; diff --git a/components/StationDiagram/ExGridViewItem.tsx b/components/StationDiagram/ExGridViewItem.tsx new file mode 100644 index 0000000..db2a798 --- /dev/null +++ b/components/StationDiagram/ExGridViewItem.tsx @@ -0,0 +1,268 @@ +import { migrateTrainName } from "@/lib/eachTrainInfoCoreLib/migrateTrainName"; +import { getStringConfig, typeID } from "@/lib/getStringConfig"; +import { getTrainType } from "@/lib/getTrainType"; +import { useAllTrainDiagram } from "@/stateBox/useAllTrainDiagram"; +import { FC, useEffect, useLayoutEffect, useMemo, useState } from "react"; +import { + View, + Text, + TouchableOpacity, + useWindowDimensions, +} from "react-native"; +import { customTrainDataDetector } from "../custom-train-data"; +import dayjs from "dayjs"; +import { SheetManager } from "react-native-actions-sheet"; +import { useNavigation } from "@react-navigation/native"; +import { lineList } from "@/lib/getStationList"; +import { useStationList } from "@/stateBox/useStationList"; +import { SharedValue, useAnimatedStyle } from "react-native-reanimated"; +import Animated from "react-native-reanimated"; +import lineColorList from "@/assets/originData/lineColorList"; + +export const ExGridViewItem: FC<{ + d: { + trainNumber: string; + array: string; + name: string; + timeType: string; + time: string; + isOperating: boolean; + }; + index: number; + width: SharedValue; + array: { + train: string; + lastStation: string; + time: string; + isThrough?: boolean; + }[]; +}> = ({ d, index, width, array }) => { + const { allCustomTrainData } = useAllTrainDiagram(); + const { originalStationList, stationList } = useStationList(); + const { navigate, goBack } = useNavigation(); + const [trainData, setTrainData] = useState<{ + ToData: string; + TrainNumber: string; + id: string; + img: string; + info?: string; + infoUrl: string; + infogram: string; + isEdit: boolean; + isSeason: boolean; + trainName: string; + trainNumDistance?: number; + type: typeID; + viaData?: string; + uwasa?: string; + }>(); + useEffect(() => { + if (allCustomTrainData) { + allCustomTrainData.forEach((x) => { + if (x.TrainNumber === d.trainNumber) { + setTrainData(x); + } + }); + } + }, []); + const { color, name, data } = getTrainType(trainData?.type, true); + // 列車名、種別、フォントの取得 + const [ + typeString, + trainName, + fontAvailable, + isOneMan, + infogram, + isEdit, + uwasa, + vehicleFormation, + trainInfoUrl, + ] = useMemo(() => { + const { + type, + trainName, + trainNumDistance, + infogram, + isEdit, + uwasa, + vehicleFormation, + trainInfoUrl, + } = customTrainDataDetector(d.trainNumber, allCustomTrainData); + const [typeString, fontAvailable, isOneMan] = getStringConfig( + type, + d.trainNumber + ); + const trainData = d.array.split("#").filter((d) => d !== ""); + switch (true) { + case trainData[trainData.length - 1] === undefined: + return [ + typeString, + "", + fontAvailable, + isOneMan, + infogram, + isEdit, + uwasa, + vehicleFormation, + trainInfoUrl, + ]; + default: + // 行先がある場合は、行先を取得 + const trainName = (d.timeType == "着" || d.timeType == "着編") ? trainData[0].split(",")[0] : trainData[trainData.length - 1].split(",")[0] + return [ + typeString, + migrateTrainName(trainName), + fontAvailable, + isOneMan, + infogram, + isEdit, + uwasa, + vehicleFormation, + trainInfoUrl, + ]; + } + }, [d.array]); + const timeArray = d.time.split(":").map((s) => parseInt(s)); + const formattedTime = dayjs() + .set("hour", timeArray[0]) + .set("minute", timeArray[1]) + .format("m"); + let isSameTimeBefore = false; + if (index > 0) { + const beforeItem = array[index - 1]; + const beforeTimeArray = beforeItem.time.split(":").map((s) => parseInt(s)); + const beforeFormattedTime = dayjs() + .set("hour", beforeTimeArray[0]) + .set("minute", beforeTimeArray[1]) + .format("m"); + isSameTimeBefore = beforeFormattedTime === formattedTime; + } + + const openStationACFromEachTrainInfo = async (stationName) => { + await SheetManager.hide("EachTrainInfo"); + const findStationEachLine = (selectLine) => { + let NearStation = selectLine.filter((d) => d.Station_JP == stationName); + return NearStation; + }; + let returnDataBase = lineList + .map((d) => findStationEachLine(originalStationList[d])) + .filter((d) => d.length > 0) + .reduce((pre, current) => { + pre.push(...current); + return pre; + }, []); + if (returnDataBase.length) { + const payload = { + currentStation: returnDataBase, + navigate, + //@ts-ignore + useShow: () => SheetManager.show("StationDetailView", { payload }), + onExit: () => SheetManager.hide("StationDetailView"), + }; //@ts-ignore + setTimeout(() => SheetManager.show("StationDetailView", { payload }), 50); + } else { + SheetManager.hide("StationDetailView"); + } + }; + const openTrainInfo = () => { + let TrainNumber = ""; + if (trainData.trainNumDistance != undefined) { + const timeInfo = + parseInt(trainData.TrainNumber.replace("M", "").replace("D", "")) - + trainData.trainNumDistance; + TrainNumber = timeInfo + "号"; + } + const payload = { + data: { + trainNum: trainData.TrainNumber, + limited: `${data}:${trainData.trainName}${TrainNumber}`, + }, + navigate, + openStationACFromEachTrainInfo, + from: d.isOperating ? null :"AllTrainIDList", + }; + SheetManager.show("EachTrainInfo", { + //@ts-ignore + payload, + onClose: (data) => { + //alert(data); + }, + }); + }; + const [stationColor, setStationColor] = useState(["gray"]); + useEffect(() => { + const Stations = stationList + .map((a) => a.filter((d) => d.StationName == trainName)) + .reduce((newArray, e) => newArray.concat(e), []); + const StationNumbers = + Stations && + Stations.filter((d) => d.StationNumber).map((d) => d.StationNumber); + + if (StationNumbers) { + const stationLineColor = StationNumbers.map( + (d) => lineColorList[d.charAt(0)] + ); + setStationColor(stationLineColor || ["gray"]); + } + }, [stationList]); + // if(typeString == "回送"){ + // return<>; + // } + const animatedStyle = useAnimatedStyle(() => { + const leftPosition = + ((((width.value - 50) / 100) * parseInt(formattedTime)) / 60) * 100; + return { + left: leftPosition, + }; + }, [formattedTime]); + return ( + + + openTrainInfo()}> + + {formattedTime} + + {d.timeType} + + + + + {trainName} + + + + + + ); +}; diff --git a/components/StationDiagram/ExGridViewTimePositionItem.tsx b/components/StationDiagram/ExGridViewTimePositionItem.tsx new file mode 100644 index 0000000..501a601 --- /dev/null +++ b/components/StationDiagram/ExGridViewTimePositionItem.tsx @@ -0,0 +1,44 @@ +import { FC } from "react"; +import { View } from "react-native"; +import dayjs from "dayjs"; +import { SharedValue, useAnimatedStyle } from "react-native-reanimated"; +import Animated from "react-native-reanimated"; + +export const ExGridViewTimePositionItem: FC<{ + width: SharedValue; + hour: string; +}> = ({ width, hour }) => { + const date = dayjs(); + const formattedTime = date.format("m"); + const formattedHour = date.format("H"); + + // if(typeString == "回送"){ + // return<>; + // } + const animatedStyle = useAnimatedStyle(() => { + const leftPosition = + ((((width.value - 50) / 100) * parseInt(formattedTime)) / 60) * 100; + return { + left: leftPosition, + }; + }, [formattedTime]); + if (formattedHour != hour) return <>; + return ( + + + + ); +}; diff --git a/components/StationDiagram/ListView.tsx b/components/StationDiagram/ListView.tsx new file mode 100644 index 0000000..1709333 --- /dev/null +++ b/components/StationDiagram/ListView.tsx @@ -0,0 +1,43 @@ +import { FC } from "react"; +import { ListViewItem } from "@/components/StationDiagram/ListViewItem"; +import { View, Text, ScrollView } from "react-native"; + +export const ListView: FC<{ + data: { + trainNumber: string; + array: string; + name: string; + type: string; + time: string; + }[]; +}> = ({ data }) => { + const groupedData = {}; + const groupKeys = []; + data.forEach((item) => { + const hour = item.time.split(":")[0]; + if (!groupedData[hour]) { + groupedData[hour] = []; + groupKeys.push(hour); + } + groupedData[hour].push(item); + }); + return ( + i * 2) : [] + } + > + {groupKeys.map((hour) => [ + + {hour}時台 + , + + {groupedData[hour].map((d, i) => ( + + ))} + , + ])} + + ); +}; diff --git a/components/StationDiagram/ListViewItem.tsx b/components/StationDiagram/ListViewItem.tsx new file mode 100644 index 0000000..7e1e50e --- /dev/null +++ b/components/StationDiagram/ListViewItem.tsx @@ -0,0 +1,244 @@ +import { migrateTrainName } from "@/lib/eachTrainInfoCoreLib/migrateTrainName"; +import { getStringConfig, typeID } from "@/lib/getStringConfig"; +import { getTrainType } from "@/lib/getTrainType"; +import { useAllTrainDiagram } from "@/stateBox/useAllTrainDiagram"; +import { FC, useEffect, useMemo, useState } from "react"; +import { View, Text, TouchableOpacity } from "react-native"; +import { customTrainDataDetector } from "../custom-train-data"; +import dayjs from "dayjs"; +import { SheetManager } from "react-native-actions-sheet"; +import { useNavigation } from "@react-navigation/native"; +import { lineList } from "@/lib/getStationList"; +import { useStationList } from "@/stateBox/useStationList"; + +export const ListViewItem: FC<{ + d: { + trainNumber: string; + array: string; + name: string; + type: string; + time: string; + }; +}> = ({ d }) => { + const { allCustomTrainData } = useAllTrainDiagram(); + const { navigate, goBack } = useNavigation(); + const [trainData, setTrainData] = useState<{ + ToData: string; + TrainNumber: string; + id: string; + img: string; + info?: string; + infoUrl: string; + infogram: string; + isEdit: boolean; + isSeason: boolean; + trainName: string; + trainNumDistance?: number; + type: typeID; + viaData?: string; + uwasa?: string; + }>(); + useEffect(() => { + if (allCustomTrainData) { + allCustomTrainData.forEach((x) => { + if (x.TrainNumber === d.trainNumber) { + setTrainData(x); + } + }); + } + }, []); + const { color, name, data } = getTrainType(trainData?.type, true); + const { originalStationList } = useStationList(); + // 列車名、種別、フォントの取得 + const [ + typeString, + trainName, + fontAvailable, + isOneMan, + infogram, + isEdit, + uwasa, + vehicleFormation, + trainInfoUrl, + ] = useMemo(() => { + const { + type, + trainName, + trainNumDistance, + infogram, + isEdit, + uwasa, + vehicleFormation, + trainInfoUrl, + } = customTrainDataDetector(d.trainNumber, allCustomTrainData); + const [typeString, fontAvailable, isOneMan] = getStringConfig( + type, + d.trainNumber + ); + const trainData = d.array.split("#").filter((d) => d !== ""); + switch (true) { + case trainData[trainData.length - 1] === undefined: + return [ + typeString, + "", + fontAvailable, + isOneMan, + infogram, + isEdit, + uwasa, + vehicleFormation, + trainInfoUrl, + ]; + default: + // 行先がある場合は、行先を取得 + return [ + typeString, + migrateTrainName( + trainData[trainData.length - 1].split(",")[0] + "行き" + ), + fontAvailable, + isOneMan, + infogram, + isEdit, + uwasa, + vehicleFormation, + trainInfoUrl, + ]; + } + }, [d.array]); + const timeArray = d.time.split(":").map((s) => parseInt(s)); + const formattedTime = dayjs() + .set("hour", timeArray[0]) + .set("minute", timeArray[1]) + .format("HH:mm"); + + const openStationACFromEachTrainInfo = async (stationName) => { + await SheetManager.hide("EachTrainInfo"); + const findStationEachLine = (selectLine) => { + let NearStation = selectLine.filter((d) => d.Station_JP == stationName); + return NearStation; + }; + let returnDataBase = lineList + .map((d) => findStationEachLine(originalStationList[d])) + .filter((d) => d.length > 0) + .reduce((pre, current) => { + pre.push(...current); + return pre; + }, []); + if (returnDataBase.length) { + const payload = { + currentStation: returnDataBase, + navigate, + //@ts-ignore + useShow: () => SheetManager.show("StationDetailView", { payload }), + onExit: () => SheetManager.hide("StationDetailView"), + };//@ts-ignore + setTimeout(() => SheetManager.show("StationDetailView", { payload }), 50); + } else { + SheetManager.hide("StationDetailView"); + } + }; + const openTrainInfo = () => { + let TrainNumber = ""; + if (trainData.trainNumDistance != undefined) { + const timeInfo = + parseInt(trainData.TrainNumber.replace("M", "").replace("D", "")) - + trainData.trainNumDistance; + TrainNumber = timeInfo + "号"; + } + const payload = { + data: { + trainNum: trainData.TrainNumber, + limited: `${data}:${trainData.trainName}${TrainNumber}`, + }, + navigate, + openStationACFromEachTrainInfo, + from: "AllTrainIDList", + }; + SheetManager.show("EachTrainInfo", { + //@ts-ignore + payload, + onClose: (data) => { + //alert(data); + }, + }); + }; + return ( + openTrainInfo()} + > + + {formattedTime} + + {d.type} + + + + + + {typeString} + + + {trainData?.trainName + + (trainData?.trainNumDistance !== null + ? ` ${parseInt(d.trainNumber) - trainData?.trainNumDistance}号` + : "")} + + + {trainData?.TrainNumber} + + + + {trainName} + + + + ); +}; diff --git a/components/StationDiagram/StationDiagramView.tsx b/components/StationDiagram/StationDiagramView.tsx new file mode 100644 index 0000000..3ce86ca --- /dev/null +++ b/components/StationDiagram/StationDiagramView.tsx @@ -0,0 +1,454 @@ +import { FC, useEffect, useState } from "react"; +import { + View, + Text, + ScrollView, + TextInput, + Keyboard, + KeyboardAvoidingView, + Platform, + TouchableOpacity, + LayoutAnimation, +} from "react-native"; +import { useNavigation } from "@react-navigation/native"; +import { BigButton } from "../atom/BigButton"; +import { useAllTrainDiagram } from "@/stateBox/useAllTrainDiagram"; +import { ListView } from "@/components/StationDiagram/ListView"; +import dayjs from "dayjs"; +import { ExGridView } from "./ExGridView"; +import { Switch } from "react-native-elements"; +import { customTrainDataDetector } from "../custom-train-data"; +import { typeID } from "@/lib/getStringConfig"; +import { colorString } from "@/lib/getTrainType"; + +type props = { + route: { + params: { + currentStation: { + Station_JP: string; + Station_EN: string; + StationName?: string; + MyStation?: string; + StationNumber: string; + DispNum?: string; + StationTimeTable: string; + StationMap?: string; + JrHpUrl?: string; + lat: number; + lng: number; + jslodApi: string; + }[]; + }; + }; +}; +export const StationDiagramView: FC = ({ route }) => { + if (!route.params) { + return null; + } + const { currentStation } = route.params; + // 必要な情報:駅情報、全ダイヤ、カスタム列車情報 + // 表示モード:縦並びリスト、横並びグリッド(時刻分割)、横並び単純左詰め + // フィルタリング:終点路線、種別、行先、関係停車駅 + + const { keyList, allTrainDiagram, allCustomTrainData } = useAllTrainDiagram(); + + const { navigate, addListener, goBack, canGoBack } = useNavigation(); + const [keyBoardVisible, setKeyBoardVisible] = useState(false); + const [input, setInput] = useState(""); + const [selectedTypeList, setSelectedTypeList] = useState([ + "Normal", + "OneMan", + "Rapid", + "OneManRapid", + "LTDEXP", + "NightLTDEXP", + ]); + type hoge = { + trainNumber: string; + array: string; + name: string; + timeType: string; + time: string; + }[]; + const [showTypeFiltering, setShowTypeFiltering] = useState(false); + const [showLastStop, setShowLastStop] = useState(false); + const [threw, setIsThrew] = useState(false); + const [currentStationDiagram, setCurrentStationDiagram] = useState([]); + useEffect(() => { + if (allTrainDiagram && currentStation.length > 0) { + const stationName = currentStation[0].Station_JP; + let returnDataArray: hoge = []; + keyList + .filter((s) => { + const boolData = allTrainDiagram[s]; + let isStop = false; + let isInput = false; + + boolData.split("#").forEach((d) => { + const [station, type, time] = d.split(","); + if (station === stationName) isStop = true; + if (station === input && type && !type.includes("通")) + isInput = true; + }); + if (input && input.length > 0) { + return isInput && isStop; + } + return isStop; + }) + .forEach((d) => { + allTrainDiagram[d] + .split("#") + .filter((d) => { + const [station, type, time] = d.split(","); + return station === stationName; + }) + .forEach((x) => { + const [name, timeType, time] = x.split(","); + if (!name || !timeType || !time) return; + + const { img, trainName, type, trainNumDistance, infogram } = + customTrainDataDetector(d, allCustomTrainData); + const arrayData = { + trainNumber: d, + array: allTrainDiagram[d], + name, + timeType, + time, + }; + // //条件によってフィルタリング + if (!threw && timeType && timeType.includes("通")) return; + if (!showLastStop && timeType && timeType.includes("着")) return; + if ( + selectedTypeList.length > 0 && + selectedTypeList.findIndex((item) => item === type) === -1 + ) { + if ( + selectedTypeList.findIndex( + (item) => item === "Forwarding" + ) !== -1 + ) { + if (!d.match(/[A,B,R,H,E,T,L]/)) return; + } else if ( + selectedTypeList.findIndex((item) => item === "SPCL") !== -1 + ) { + if (!d.match(/9\d\d\d[D,M,S]/)) return; + } else { + return; + } + } + returnDataArray.push(arrayData); + }); + }); + setCurrentStationDiagram( + returnDataArray.sort((a, b) => { + const adjustTime = (t: string) => { + const [h, m] = t.split(":").map(Number); + // 4時未満は翌日の時刻とみなして+24時間 + return h < 4 + ? dayjs().add(1, "day").hour(h).minute(m) + : dayjs().hour(h).minute(m); + }; + const aa = adjustTime(a.time); + const bb = adjustTime(b.time); + const x = aa.isAfter(bb); + return x ? 1 : -1; + //return true; + }) + ); + } + }, [currentStation, showLastStop, threw, input, selectedTypeList]); + + useEffect(() => { + const showSubscription = Keyboard.addListener("keyboardDidShow", () => { + setKeyBoardVisible(true); + }); + const hideSubscription = Keyboard.addListener("keyboardDidHide", () => { + setKeyBoardVisible(false); + }); + + return () => { + showSubscription.remove(); + hideSubscription.remove(); + }; + }, []); + return ( + + + {currentStation[0].Station_JP}駅 時刻表 + + {/* */} + + {/* + お気に入り登録した駅のうち、位置情報システムで移動可能な駅が表示されています。タップすることで位置情報システムの当該の駅に移動します。 + */} + + + { + setIsThrew(!threw); + }} + > + + 通過 + + + { + setShowLastStop(!showLastStop); + }} + > + + 当駅止 + + + + {showTypeFiltering ? ( + <> + + + + + + + { + LayoutAnimation.configureNext( + LayoutAnimation.Presets.easeInEaseOut + ); + setShowTypeFiltering(false); + }} + > + + < + + + + ) : ( + { + LayoutAnimation.configureNext( + LayoutAnimation.Presets.easeInEaseOut + ); + setShowTypeFiltering(true); + }} + > + + > + + + )} + + + setKeyBoardVisible(true)} + onEndEditing={() => {}} + onChange={(ret) => setInput(ret.nativeEvent.text)} + value={input} + style={{ flex: 1 }} + /> + + + {keyBoardVisible || ( + goBack()} string="閉じる" /> + )} + + ); +}; + +export const TypeSelectorBox: FC<{ + selectedTypeList: typeID[]; + setSelectedTypeList: (list: typeID[]) => void; + typeName: string; + typeID: typeID; + color: colorString; + relativeID?: typeID[]; +}> = (props) => { + const { + selectedTypeList, + setSelectedTypeList, + typeName, + typeID, + relativeID, + color, + } = props; + const isSelected = + selectedTypeList.findIndex((item) => item === typeID) !== -1; + return ( + { + if (selectedTypeList.findIndex((item) => item === typeID) === -1) { + setSelectedTypeList([ + ...selectedTypeList, + typeID, + ...(relativeID ?? []), + ]); + } else { + setSelectedTypeList( + selectedTypeList.filter( + (item) => item !== typeID && !relativeID?.includes(item) + ) + ); + } + }} + > + + {typeName} + + + ); +}; diff --git a/lib/getStringConfig.ts b/lib/getStringConfig.ts index 327c533..54f84a9 100644 --- a/lib/getStringConfig.ts +++ b/lib/getStringConfig.ts @@ -1,4 +1,4 @@ -type typeID = +export type typeID = | "Normal" | "OneMan" | "Rapid" diff --git a/lib/getTrainType.ts b/lib/getTrainType.ts index 7966b8a..99450f9 100644 --- a/lib/getTrainType.ts +++ b/lib/getTrainType.ts @@ -1,11 +1,17 @@ -type nameString = - | "Rapid" - | "LTDEXP" - | "NightLTDEXP" - | "SPCL" - | "Normal" - | string; -type colorString = "aqua" | "red" | "#297bff" | "#ff7300ff" | "#00869ecc" | "#727272cc" | "white" | "pink"; +import { typeID } from "./getStringConfig"; + +export type colorString = + | "aqua" + | "red" + | "#297bff" + | "#ff7300ff" + | "#00869ecc" + | "#727272cc" + | "#00b8d8cc" + | "#e000b0ff" + | "white" + | "black" + | "pink"; type trainTypeString = | "快速" | "特急" @@ -21,24 +27,35 @@ type trainTypeString = | "単機回送" | "その他"; type trainTypeDataString = "rapid" | "express" | "normal" | "notService"; -type getTrainType = (d: nameString) => { +type getTrainType = ( + d: typeID, + isWhiteMode?: boolean +) => { color: colorString; name: trainTypeString; data: trainTypeDataString; }; -export const getTrainType: getTrainType = (nameString) => { +export const getTrainType: getTrainType = (nameString, whiteMode) => { switch (nameString) { case "Normal": - return { color: "white", name: "普通列車", data: "normal" }; + return { + color: whiteMode ? "black" : "white", + name: "普通列車", + data: "normal", + }; case "OneMan": - return { color: "white", name: "普通列車(ワンマン)", data: "normal" }; + return { + color: whiteMode ? "black" : "white", + name: "普通列車(ワンマン)", + data: "normal", + }; case "Rapid": case "OneManRapid": - return { color: "aqua", name: "快速", data: "rapid" }; + return { color: whiteMode ? "#00b8d8cc" : "aqua", name: "快速", data: "rapid" }; case "LTDEXP": return { color: "red", name: "特急", data: "express" }; case "NightLTDEXP": - return { color: "pink", name: "寝台特急", data: "express" }; + return { color: whiteMode ? "#e000b0ff":"pink", name: "寝台特急", data: "express" }; case "SPCL": case "SPCL_Normal": return { color: "#297bff", name: "臨時", data: "normal" }; @@ -55,6 +72,10 @@ export const getTrainType: getTrainType = (nameString) => { case "FreightForwarding": return { color: "#727272cc", name: "単機回送", data: "notService" }; default: - return { color: "white", name: "その他", data: "normal" }; + return { + color: whiteMode ? "black" : "white", + name: "その他", + data: "normal", + }; } }; diff --git a/stateBox/useAllTrainDiagram.js b/stateBox/useAllTrainDiagram.js index a569f3d..a1f80de 100644 --- a/stateBox/useAllTrainDiagram.js +++ b/stateBox/useAllTrainDiagram.js @@ -6,6 +6,7 @@ const initialState = { allTrainDiagram: undefined, setAllTrainDiagram: () => {}, allCustomTrainData: [], + keyList: [], }; const AllTrainDiagramContext = createContext(initialState);