Merge commit '63ae4e8c14576270b3678df7e6210099aadb627a' into develop
This commit is contained in:
14
MenuPage.js
14
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() {
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name="stDiagram"
|
||||
options={{ ...optionData, gestureEnabled: false }}
|
||||
component={StationDiagramView}
|
||||
/>
|
||||
<Stack.Screen name="news" options={optionData} component={News} />
|
||||
<Stack.Screen
|
||||
name="setting"
|
||||
@@ -133,7 +139,11 @@ export function MenuPage() {
|
||||
component={AllTrainDiagramView}
|
||||
/>
|
||||
<Stack.Screen name="howto" options={optionData} component={HowTo} />
|
||||
<Stack.Screen name="generalWebView" options={optionData} component={GeneralWebView} />
|
||||
<Stack.Screen
|
||||
name="generalWebView"
|
||||
options={optionData}
|
||||
component={GeneralWebView}
|
||||
/>
|
||||
</Stack.Navigator>
|
||||
);
|
||||
}
|
||||
|
15
Top.js
15
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}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name="stDiagram"
|
||||
options={{ ...optionData, gestureEnabled: false }}
|
||||
component={StationDiagramView}
|
||||
/>
|
||||
<Stack.Screen name="howto" options={optionData} component={HowTo} />
|
||||
<Stack.Screen name="generalWebView" options={optionData} component={GeneralWebView} />
|
||||
<Stack.Screen
|
||||
name="generalWebView"
|
||||
options={optionData}
|
||||
component={GeneralWebView}
|
||||
/>
|
||||
<Stack.Screen name="news" options={optionData} component={News} />
|
||||
<Stack.Screen
|
||||
name="trainMenu"
|
||||
|
@@ -19,6 +19,7 @@ import { 駅構内図 } from "./StationDeteilView/StationInsideMapButton";
|
||||
import { WebSiteButton } from "./StationDeteilView/WebSiteButton";
|
||||
import { StationTimeTableButton } from "./StationDeteilView/StationTimeTableButton";
|
||||
import { StationTrainPositionButton } from "./StationDeteilView/StationTrainPositionButton";
|
||||
import { StationDiagramButton } from "./StationDeteilView/StationDiagramButton";
|
||||
|
||||
export const StationDeteilView = (props) => {
|
||||
if (!props.payload) return <></>;
|
||||
@@ -132,6 +133,11 @@ export const StationDeteilView = (props) => {
|
||||
onExit={onExit}
|
||||
/>
|
||||
)}
|
||||
<StationDiagramButton
|
||||
navigate={navigate}
|
||||
onExit={onExit}
|
||||
currentStation={currentStation}
|
||||
/>
|
||||
{!currentStation[0].StationTimeTable || (
|
||||
<StationTimeTableButton
|
||||
info={info}
|
||||
|
@@ -0,0 +1,40 @@
|
||||
import React, { FC } from "react";
|
||||
import { Linking } from "react-native";
|
||||
import { FontAwesome } from "@expo/vector-icons";
|
||||
import { TicketBox } from "@/components/atom/TicketBox";
|
||||
type Props = {
|
||||
navigate: (screen: string, params?: object) => 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> = (props) => {
|
||||
const { navigate, onExit, currentStation } = props;
|
||||
return (
|
||||
<TicketBox
|
||||
backgroundColor={"#8F5902"}
|
||||
icon={<FontAwesome name="table" color="white" size={50} />}
|
||||
flex={1}
|
||||
onPressButton={() => {
|
||||
navigate("stDiagram", {
|
||||
currentStation,
|
||||
});
|
||||
onExit();
|
||||
}}
|
||||
>
|
||||
時刻表v2
|
||||
</TicketBox>
|
||||
);
|
||||
};
|
355
components/StationDiagram/ExGridView.tsx
Normal file
355
components/StationDiagram/ExGridView.tsx
Normal file
@@ -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<Animated.ScrollView>(null);
|
||||
const scrollRef2 = useRef<Animated.ScrollView>(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 (
|
||||
<>
|
||||
<Animated.View
|
||||
style={[
|
||||
{
|
||||
position: "absolute",
|
||||
width,
|
||||
backgroundColor: "#26d1baff",
|
||||
zIndex: 500,
|
||||
top: 0,
|
||||
},
|
||||
animatedLongPressStyle,
|
||||
]}
|
||||
entering={FadeInUp}
|
||||
exiting={FadeOutUp}
|
||||
>
|
||||
<Text style={{ fontSize: 30, textAlign: "center", flex: 1 }}>
|
||||
↑縮小 ・ 拡大↓
|
||||
</Text>
|
||||
</Animated.View>
|
||||
<GestureDetector gesture={composed}>
|
||||
<Animated.ScrollView
|
||||
horizontal
|
||||
nestedScrollEnabled
|
||||
pinchGestureEnabled={false}
|
||||
scrollEnabled={scrollEnabled}
|
||||
onScroll={scrollHandler}
|
||||
onContentSizeChange={(contentWidth) => {
|
||||
// 現在のスクロール位置を取得
|
||||
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",
|
||||
}}
|
||||
>
|
||||
<Animated.View
|
||||
style={[
|
||||
{
|
||||
width: width,
|
||||
flexDirection: "row",
|
||||
},
|
||||
animatedStyle,
|
||||
]}
|
||||
>
|
||||
{Array.from({ length: 60 }, (_, i) => i + 1).map((num) => {
|
||||
if (num % 5 === 0) {
|
||||
return (
|
||||
<Text
|
||||
key={num}
|
||||
style={{
|
||||
flex: 1,
|
||||
textAlign: "left",
|
||||
borderRightWidth: 0.5,
|
||||
borderColor: "#ccc",
|
||||
flexWrap: "nowrap",
|
||||
fontSize: 12,
|
||||
}}
|
||||
>
|
||||
{num - 5}
|
||||
</Text>
|
||||
);
|
||||
} else return <></>;
|
||||
})}
|
||||
<Text
|
||||
style={{
|
||||
textAlign: "right",
|
||||
borderRightWidth: 0.5,
|
||||
borderColor: "#ccc",
|
||||
flexWrap: "nowrap",
|
||||
fontSize: 12,
|
||||
width: 50,
|
||||
}}
|
||||
>
|
||||
(分)
|
||||
</Text>
|
||||
</Animated.View>
|
||||
<Animated.ScrollView
|
||||
style={[{ width: width }, animatedStyle]}
|
||||
pinchGestureEnabled={false}
|
||||
minimumZoomScale={0.5}
|
||||
maximumZoomScale={3.0}
|
||||
scrollEnabled={scrollEnabled}
|
||||
stickyHeaderIndices={
|
||||
groupKeys.at(0) ? groupKeys.map((_, i) => i * 2) : []
|
||||
}
|
||||
ref={scrollRef2}
|
||||
>
|
||||
{groupKeys.map((hour) => [
|
||||
<View
|
||||
style={{
|
||||
padding: 5,
|
||||
borderBottomWidth: 0.5,
|
||||
borderTopWidth: 0.5,
|
||||
borderBottomColor: "#ccc",
|
||||
backgroundColor: "#f0f0f0",
|
||||
}}
|
||||
key={hour}
|
||||
>
|
||||
<Animated.Text
|
||||
style={[
|
||||
{
|
||||
fontSize: 15,
|
||||
zIndex: 1,
|
||||
marginLeft: 0,
|
||||
},
|
||||
stickyTextStyle,
|
||||
]}
|
||||
>
|
||||
{hour}時台
|
||||
</Animated.Text>
|
||||
</View>,
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
position: "relative",
|
||||
height: 50,
|
||||
}}
|
||||
>
|
||||
{groupedData[hour].map((d, i, array) => (
|
||||
<ExGridViewItem
|
||||
key={d.trainNumber + i}
|
||||
d={d}
|
||||
index={i}
|
||||
width={widthX}
|
||||
array={array}
|
||||
/>
|
||||
))}
|
||||
<ExGridViewTimePositionItem width={widthX} hour={hour} />
|
||||
</View>,
|
||||
])}
|
||||
</Animated.ScrollView>
|
||||
</Animated.ScrollView>
|
||||
</GestureDetector>
|
||||
</>
|
||||
);
|
||||
};
|
268
components/StationDiagram/ExGridViewItem.tsx
Normal file
268
components/StationDiagram/ExGridViewItem.tsx
Normal file
@@ -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<number>;
|
||||
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 (
|
||||
<View style={{ left: 0, height: 50 }}>
|
||||
<Animated.View
|
||||
style={[
|
||||
{
|
||||
flexDirection: "column",
|
||||
//borderTopWidth: 1,
|
||||
//borderBottomWidth: 0.5,
|
||||
borderStyle: "solid",
|
||||
borderColor: "darkgray",
|
||||
opacity: d.timeType.includes("通") ? 0.5 : 1,
|
||||
position: "absolute",
|
||||
height: "100%",
|
||||
width: 28,
|
||||
top: isSameTimeBefore ? 10 : 0,
|
||||
},
|
||||
animatedStyle,
|
||||
]}
|
||||
>
|
||||
<TouchableOpacity style={{ flex: 1 }} onPress={() => openTrainInfo()}>
|
||||
<View style={{ position: "relative" }}>
|
||||
<Text style={{ fontSize: 20, color: color, opacity: isSameTimeBefore ? 0 : 1, fontWeight:d.isOperating ? "bold" : "thin", fontStyle:d.isOperating? "italic" :"normal" }}>{formattedTime}</Text>
|
||||
<Text
|
||||
style={{
|
||||
fontSize: 10,
|
||||
position: "absolute",
|
||||
bottom: 0,
|
||||
right: 0,
|
||||
fontWeight: "bold",
|
||||
}}
|
||||
>
|
||||
{d.timeType}
|
||||
</Text>
|
||||
</View>
|
||||
<View style={{ flex: 1, flexDirection: "column" }}>
|
||||
<Text
|
||||
style={{
|
||||
fontSize: 8,
|
||||
flex: 1,
|
||||
fontWeight: "bold",
|
||||
color: stationColor[0],
|
||||
}}
|
||||
>
|
||||
{trainName}
|
||||
</Text>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
</Animated.View>
|
||||
</View>
|
||||
);
|
||||
};
|
44
components/StationDiagram/ExGridViewTimePositionItem.tsx
Normal file
44
components/StationDiagram/ExGridViewTimePositionItem.tsx
Normal file
@@ -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<number>;
|
||||
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 (
|
||||
<View style={{ left: 0, height: 50, width: 1 }}>
|
||||
<Animated.View
|
||||
style={[
|
||||
{
|
||||
flexDirection: "column",
|
||||
borderLeftWidth: 2,
|
||||
//borderBottomWidth: 0.5,
|
||||
borderStyle: "solid",
|
||||
borderColor: "red",
|
||||
position: "absolute",
|
||||
height: "100%",
|
||||
},
|
||||
animatedStyle,
|
||||
]}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
};
|
43
components/StationDiagram/ListView.tsx
Normal file
43
components/StationDiagram/ListView.tsx
Normal file
@@ -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 (
|
||||
<ScrollView
|
||||
style={{ backgroundColor: "white" }}
|
||||
stickyHeaderIndices={
|
||||
groupKeys.at(0) ? groupKeys.map((_, i) => i * 2) : []
|
||||
}
|
||||
>
|
||||
{groupKeys.map((hour) => [
|
||||
<View style={{ backgroundColor: "white", padding: 5, borderBottomWidth: 0.5, borderTopWidth: 0.5, borderBottomColor: "#ccc" }} key={hour}>
|
||||
<Text style={{ fontSize: 15 }}>{hour}時台</Text>
|
||||
</View>,
|
||||
<View>
|
||||
{groupedData[hour].map((d, i) => (
|
||||
<ListViewItem key={d.trainNumber + i} d={d} />
|
||||
))}
|
||||
</View>,
|
||||
])}
|
||||
</ScrollView>
|
||||
);
|
||||
};
|
244
components/StationDiagram/ListViewItem.tsx
Normal file
244
components/StationDiagram/ListViewItem.tsx
Normal file
@@ -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 (
|
||||
<TouchableOpacity
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
marginHorizontal: 10,
|
||||
borderTopWidth: 1,
|
||||
borderBottomWidth: 0.5,
|
||||
borderStyle: "solid",
|
||||
borderColor: "darkgray",
|
||||
padding: 10,
|
||||
opacity: d.type.includes("通") ? 0.5 : 1,
|
||||
}}
|
||||
onPress={() => openTrainInfo()}
|
||||
>
|
||||
<View style={{ position: "relative" }}>
|
||||
<Text style={{ fontSize: 30 }}>{formattedTime}</Text>
|
||||
<Text
|
||||
style={{
|
||||
fontSize: 10,
|
||||
position: "absolute",
|
||||
bottom: -3,
|
||||
right: 0,
|
||||
fontWeight: "bold",
|
||||
}}
|
||||
>
|
||||
{d.type}
|
||||
</Text>
|
||||
</View>
|
||||
<View style={{ flex: 1, flexDirection: "column" }}>
|
||||
<View style={{ flexDirection: "row" }}>
|
||||
<Text
|
||||
style={{
|
||||
fontSize: 15,
|
||||
fontFamily: fontAvailable ? "JR-Nishi" : undefined,
|
||||
fontWeight: !fontAvailable ? "bold" : undefined,
|
||||
paddingTop: fontAvailable ? 2 : 0,
|
||||
paddingLeft: 10,
|
||||
color: color,
|
||||
}}
|
||||
>
|
||||
{typeString}
|
||||
</Text>
|
||||
<Text
|
||||
style={{
|
||||
fontSize: 15,
|
||||
fontWeight: "bold",
|
||||
flex: 1,
|
||||
paddingLeft: 2,
|
||||
color: color,
|
||||
}}
|
||||
>
|
||||
{trainData?.trainName +
|
||||
(trainData?.trainNumDistance !== null
|
||||
? ` ${parseInt(d.trainNumber) - trainData?.trainNumDistance}号`
|
||||
: "")}
|
||||
</Text>
|
||||
<Text
|
||||
style={{
|
||||
fontSize: 15,
|
||||
fontWeight: "bold",
|
||||
}}
|
||||
>
|
||||
{trainData?.TrainNumber}
|
||||
</Text>
|
||||
</View>
|
||||
<Text
|
||||
style={{
|
||||
fontSize: 15,
|
||||
flex: 1,
|
||||
paddingHorizontal: 10,
|
||||
fontWeight: "bold",
|
||||
}}
|
||||
>
|
||||
{trainName}
|
||||
</Text>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
};
|
454
components/StationDiagram/StationDiagramView.tsx
Normal file
454
components/StationDiagram/StationDiagramView.tsx
Normal file
@@ -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<props> = ({ 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<typeID[]>([
|
||||
"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<hoge>([]);
|
||||
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 (
|
||||
<View style={{ height: "100%", backgroundColor: "#0099CC" }}>
|
||||
<Text
|
||||
style={{
|
||||
textAlign: "center",
|
||||
fontSize: 20,
|
||||
color: "white",
|
||||
fontWeight: "bold",
|
||||
paddingVertical: 10,
|
||||
}}
|
||||
>
|
||||
{currentStation[0].Station_JP}駅 時刻表
|
||||
</Text>
|
||||
{/* <ListView data={currentStationDiagram} /> */}
|
||||
<ExGridView data={currentStationDiagram} />
|
||||
{/* <Text
|
||||
style={{
|
||||
backgroundColor: "white",
|
||||
borderWidth: 1,
|
||||
borderStyle: "solid",
|
||||
}}
|
||||
>
|
||||
お気に入り登録した駅のうち、位置情報システムで移動可能な駅が表示されています。タップすることで位置情報システムの当該の駅に移動します。
|
||||
</Text> */}
|
||||
<KeyboardAvoidingView
|
||||
behavior="padding"
|
||||
keyboardVerticalOffset={80}
|
||||
enabled={Platform.OS === "ios"}
|
||||
>
|
||||
<ScrollView horizontal style={{ height: 35, flexDirection: "row" }}>
|
||||
<TouchableOpacity
|
||||
style={{
|
||||
alignItems: "center",
|
||||
marginHorizontal: 5,
|
||||
backgroundColor: threw ? "white" : "#ffffff00",
|
||||
alignSelf: "center",
|
||||
borderColor: "white",
|
||||
borderWidth: 1,
|
||||
borderRadius: 100,
|
||||
}}
|
||||
onPress={() => {
|
||||
setIsThrew(!threw);
|
||||
}}
|
||||
>
|
||||
<Text
|
||||
style={{
|
||||
color: threw ? "#0099CC" : "white",
|
||||
fontSize: 14,
|
||||
margin: 5,
|
||||
}}
|
||||
>
|
||||
通過
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
style={{
|
||||
alignItems: "center",
|
||||
marginHorizontal: 5,
|
||||
backgroundColor: showLastStop ? "white" : "#ffffff00",
|
||||
alignSelf: "center",
|
||||
borderColor: "white",
|
||||
borderWidth: 1,
|
||||
borderRadius: 100,
|
||||
}}
|
||||
onPress={() => {
|
||||
setShowLastStop(!showLastStop);
|
||||
}}
|
||||
>
|
||||
<Text
|
||||
style={{
|
||||
color: showLastStop ? "#0099CC" : "white",
|
||||
fontSize: 14,
|
||||
margin: 5,
|
||||
}}
|
||||
>
|
||||
当駅止
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
<View
|
||||
style={{
|
||||
height: "auto",
|
||||
borderLeftWidth: 1,
|
||||
margin: 5,
|
||||
borderColor: "white",
|
||||
}}
|
||||
/>
|
||||
{showTypeFiltering ? (
|
||||
<>
|
||||
<TypeSelectorBox
|
||||
selectedTypeList={selectedTypeList}
|
||||
setSelectedTypeList={setSelectedTypeList}
|
||||
typeName="普通"
|
||||
typeID="Normal"
|
||||
color="black"
|
||||
relativeID={["OneMan"]}
|
||||
/>
|
||||
<TypeSelectorBox
|
||||
selectedTypeList={selectedTypeList}
|
||||
setSelectedTypeList={setSelectedTypeList}
|
||||
typeName="快速"
|
||||
typeID="Rapid"
|
||||
color="#00b8d8cc"
|
||||
relativeID={["OneManRapid"]}
|
||||
/>
|
||||
<TypeSelectorBox
|
||||
selectedTypeList={selectedTypeList}
|
||||
setSelectedTypeList={setSelectedTypeList}
|
||||
typeName="特急"
|
||||
typeID="LTDEXP"
|
||||
color="red"
|
||||
relativeID={["NightLTDEXP"]}
|
||||
/>
|
||||
<TypeSelectorBox
|
||||
selectedTypeList={selectedTypeList}
|
||||
setSelectedTypeList={setSelectedTypeList}
|
||||
typeName="臨時"
|
||||
typeID="SPCL"
|
||||
color="#297bff"
|
||||
relativeID={["SPCL_Normal", "SPCL_Rapid", "SPCL_EXP", "Party"]}
|
||||
/>
|
||||
<TypeSelectorBox
|
||||
selectedTypeList={selectedTypeList}
|
||||
setSelectedTypeList={setSelectedTypeList}
|
||||
typeName="貨物"
|
||||
typeID="Freight"
|
||||
color="#00869ecc"
|
||||
/>
|
||||
<TypeSelectorBox
|
||||
selectedTypeList={selectedTypeList}
|
||||
setSelectedTypeList={setSelectedTypeList}
|
||||
typeName="回送"
|
||||
typeID="Forwarding"
|
||||
color="#727272cc"
|
||||
relativeID={["FreightForwarding"]}
|
||||
/>
|
||||
<TouchableOpacity
|
||||
style={{
|
||||
alignItems: "center",
|
||||
marginHorizontal: 5,
|
||||
backgroundColor: "#ffffff00",
|
||||
alignSelf: "center",
|
||||
borderColor: "white",
|
||||
borderWidth: 1,
|
||||
borderRadius: 100,
|
||||
}}
|
||||
onPress={() => {
|
||||
LayoutAnimation.configureNext(
|
||||
LayoutAnimation.Presets.easeInEaseOut
|
||||
);
|
||||
setShowTypeFiltering(false);
|
||||
}}
|
||||
>
|
||||
<Text
|
||||
style={{
|
||||
color: "white",
|
||||
fontSize: 14,
|
||||
margin: 5,
|
||||
}}
|
||||
>
|
||||
<
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</>
|
||||
) : (
|
||||
<TouchableOpacity
|
||||
style={{
|
||||
alignItems: "center",
|
||||
marginHorizontal: 5,
|
||||
backgroundColor: "#ffffff00",
|
||||
alignSelf: "center",
|
||||
borderColor: "white",
|
||||
borderWidth: 1,
|
||||
borderRadius: 100,
|
||||
}}
|
||||
onPress={() => {
|
||||
LayoutAnimation.configureNext(
|
||||
LayoutAnimation.Presets.easeInEaseOut
|
||||
);
|
||||
setShowTypeFiltering(true);
|
||||
}}
|
||||
>
|
||||
<Text
|
||||
style={{
|
||||
color: "white",
|
||||
fontSize: 14,
|
||||
margin: 5,
|
||||
}}
|
||||
>
|
||||
>
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
</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>
|
||||
{keyBoardVisible || (
|
||||
<BigButton onPress={() => goBack()} string="閉じる" />
|
||||
)}
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
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 (
|
||||
<TouchableOpacity
|
||||
style={{
|
||||
alignItems: "center",
|
||||
marginHorizontal: 5,
|
||||
opacity: isSelected ? 1 : 0.8,
|
||||
backgroundColor: isSelected ? "white" : color,
|
||||
alignSelf: "center",
|
||||
borderColor: color,
|
||||
borderWidth: 1,
|
||||
borderRadius: 100,
|
||||
}}
|
||||
onPress={() => {
|
||||
if (selectedTypeList.findIndex((item) => item === typeID) === -1) {
|
||||
setSelectedTypeList([
|
||||
...selectedTypeList,
|
||||
typeID,
|
||||
...(relativeID ?? []),
|
||||
]);
|
||||
} else {
|
||||
setSelectedTypeList(
|
||||
selectedTypeList.filter(
|
||||
(item) => item !== typeID && !relativeID?.includes(item)
|
||||
)
|
||||
);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Text
|
||||
style={{
|
||||
color: isSelected ? color : "white",
|
||||
fontSize: 14,
|
||||
margin: 5,
|
||||
}}
|
||||
>
|
||||
{typeName}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
};
|
@@ -1,4 +1,4 @@
|
||||
type typeID =
|
||||
export type typeID =
|
||||
| "Normal"
|
||||
| "OneMan"
|
||||
| "Rapid"
|
||||
|
@@ -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",
|
||||
};
|
||||
}
|
||||
};
|
||||
|
@@ -6,6 +6,7 @@ const initialState = {
|
||||
allTrainDiagram: undefined,
|
||||
setAllTrainDiagram: () => {},
|
||||
allCustomTrainData: [],
|
||||
keyList: [],
|
||||
};
|
||||
|
||||
const AllTrainDiagramContext = createContext(initialState);
|
||||
|
Reference in New Issue
Block a user