メニューの地図機能の仮作成

This commit is contained in:
harukin-expo-dev-env 2025-04-13 10:35:08 +00:00
parent 44f8be994e
commit 934938287d
2 changed files with 208 additions and 366 deletions

View File

@ -1,5 +1,10 @@
import React, { useEffect } from "react"; import React, { useEffect, useRef } from "react";
import { createStackNavigator } from "@react-navigation/stack"; import { createStackNavigator } from "@react-navigation/stack";
import { useWindowDimensions, Platform } from "react-native";
import Constants from "expo-constants";
import { Dimensions, StatusBar } from "react-native";
import { SheetManager } from "react-native-actions-sheet"; import { SheetManager } from "react-native-actions-sheet";
import { AS } from "./storageControl"; import { AS } from "./storageControl";
import TrainBase from "./components/trainbaseview"; import TrainBase from "./components/trainbaseview";
@ -13,10 +18,13 @@ import AllTrainDiagramView from "./components/AllTrainDiagramView";
import { useCurrentTrain } from "./stateBox/useCurrentTrain"; import { useCurrentTrain } from "./stateBox/useCurrentTrain";
import { useNavigation } from "@react-navigation/native"; import { useNavigation } from "@react-navigation/native";
import { news } from "./config/newsUpdate"; import { news } from "./config/newsUpdate";
import { useBottomTabBarHeight } from "@react-navigation/bottom-tabs";
const Stack = createStackNavigator(); const Stack = createStackNavigator();
export function MenuPage() { export function MenuPage() {
const { favoriteStation, setFavoriteStation } = useFavoriteStation(); const { favoriteStation, setFavoriteStation } = useFavoriteStation();
const { height, width } = useWindowDimensions();
const tabBarHeight = useBottomTabBarHeight();
const { getCurrentTrain } = useCurrentTrain(); const { getCurrentTrain } = useCurrentTrain();
const navigation = useNavigation(); const navigation = useNavigation();
const { addListener } = navigation; const { addListener } = navigation;
@ -42,8 +50,20 @@ export function MenuPage() {
}) })
.catch((error) => console.error("Error fetching icon setting:", error)); .catch((error) => console.error("Error fetching icon setting:", error));
}, []); }, []);
const scrollRef = useRef(null);
const MapHeight =
height -
tabBarHeight +
(Platform.OS == "android" ? Constants.statusBarHeight : 0) -
100 -
((((width / 100) * 80) / 20) * 9 + 10 + 30);
useEffect(() => { useEffect(() => {
const unsubscribe = addListener("tabPress", (e) => { const unsubscribe = addListener("tabPress", (e) => {
scrollRef.current.scrollTo({
y: MapHeight - 80,
animated: true,
});
AS.getItem("favoriteStation") AS.getItem("favoriteStation")
.then((d) => { .then((d) => {
const returnData = JSON.parse(d); const returnData = JSON.parse(d);
@ -65,7 +85,9 @@ export function MenuPage() {
gestureEnabled: true, gestureEnabled: true,
headerTransparent: true, headerTransparent: true,
}} }}
children={() => <Menu getCurrentTrain={getCurrentTrain} />} children={() => (
<Menu getCurrentTrain={getCurrentTrain} scrollRef={scrollRef} />
)}
/> />
<Stack.Screen name="news" options={optionData} component={News} /> <Stack.Screen name="news" options={optionData} component={News} />
<Stack.Screen <Stack.Screen

248
menu.js
View File

@ -4,7 +4,6 @@ import {
Platform, Platform,
View, View,
ScrollView, ScrollView,
Linking,
Text, Text,
TouchableOpacity, TouchableOpacity,
LayoutAnimation, LayoutAnimation,
@ -18,50 +17,50 @@ import {
} from "react-native-reanimated"; } from "react-native-reanimated";
import StatusbarDetect from "./StatusbarDetect"; import StatusbarDetect from "./StatusbarDetect";
import { Ionicons } from "@expo/vector-icons"; import { Ionicons } from "@expo/vector-icons";
import LottieView from "lottie-react-native";
import LED_vision from "./components/発車時刻表/LED_vidion"; import LED_vision from "./components/発車時刻表/LED_vidion";
import Sign from "./components/駅名表/Sign"; import Sign from "./components/駅名表/Sign";
import { TitleBar } from "./components/Menu/TitleBar"; import { TitleBar } from "./components/Menu/TitleBar";
import { FixedContentBottom } from "./components/Menu/FixedContentBottom"; import { FixedContentBottom } from "./components/Menu/FixedContentBottom";
import { UsefulBox } from "./components/atom/UsefulBox";
import { lineList } from "./lib/getStationList"; import { lineList } from "./lib/getStationList";
import useInterval from "./lib/useInterval"; import useInterval from "./lib/useInterval";
import { HeaderConfig } from "./lib/HeaderConfig";
import { useFavoriteStation } from "./stateBox/useFavoriteStation"; import { useFavoriteStation } from "./stateBox/useFavoriteStation";
import { SheetManager } from "react-native-actions-sheet"; import { SheetManager } from "react-native-actions-sheet";
import { useTrainDelayData } from "./stateBox/useTrainDelayData";
import { useNavigation } from "@react-navigation/native"; import { useNavigation } from "@react-navigation/native";
import { useStationList } from "./stateBox/useStationList"; import { useStationList } from "./stateBox/useStationList";
import { StationNumber } from "./components/Menu/StationPagination"; import { StationNumber } from "./components/Menu/StationPagination";
import lineColorList from "./assets/originData/lineColorList";
import { AS } from "./storageControl"; import { AS } from "./storageControl";
import { SimpleDot } from "./components/Menu/SimpleDot"; import { SimpleDot } from "./components/Menu/SimpleDot";
import { useAllTrainDiagram } from "./stateBox/useAllTrainDiagram"; import { TopMenuButton } from "@/components/Menu/TopMenuButton";
import { JRSTraInfoBox } from "@/components/Menu/JRSTraInfoBox";
import MapView from "react-native-maps"; import MapView from "react-native-maps";
import { useSafeAreaInsets } from "react-native-safe-area-context";
import { useBottomTabBarHeight } from "@react-navigation/bottom-tabs";
configureReanimatedLogger({ configureReanimatedLogger({
level: ReanimatedLogLevel.error, // Set the log level to error level: ReanimatedLogLevel.error, // Set the log level to error
strict: true, // Reanimated runs in strict mode by default strict: true, // Reanimated runs in strict mode by default
}); });
export default function Menu({ getCurrentTrain }) { export default function Menu({ getCurrentTrain, scrollRef }) {
const { navigate } = useNavigation(); const { navigate, addListener, isFocused } = useNavigation();
const { favoriteStation } = useFavoriteStation(); const { favoriteStation } = useFavoriteStation();
const { originalStationList } = useStationList(); const { originalStationList } = useStationList();
const { height, width } = useWindowDimensions(); const { height, width } = useWindowDimensions();
const scrollRef = useRef(null); const { bottom, left, right, top } = useSafeAreaInsets();
const tabBarHeight = useBottomTabBarHeight();
const [mapsOpacity, setMapsOpacity] = useState(false); const [mapsOpacity, setMapsOpacity] = useState(false);
const mapsRef = useRef(null); const mapsRef = useRef(null);
const mapsSizeOffset = const MapHeight =
(height / 100) * 60 - height -
(((width / 100) * 80) / 20) * 9 + tabBarHeight +
60 - (Platform.OS == "android" ? Constants.statusBarHeight : 0) -
(Platform.OS == "ios" ? Constants.statusBarHeight : 0); 100 -
((((width / 100) * 80) / 20) * 9 + 10 + 30);
useEffect(() => { useEffect(() => {
setTimeout(() => { setTimeout(() => {
if (scrollRef.current) { if (scrollRef.current) {
scrollRef.current.scrollTo({ scrollRef.current.scrollTo({
y: mapsSizeOffset, y: MapHeight - 80,
animated: false, animated: false,
}); });
} }
@ -82,9 +81,9 @@ export default function Menu({ getCurrentTrain }) {
const [position, setPosition] = useState(undefined); const [position, setPosition] = useState(undefined);
const getCurrentPosition = () => { const getCurrentPosition = () => {
if (!locationStatus) return () => {}; if (!locationStatus) return () => {};
Location.getCurrentPositionAsync({}).then((location) => { Location.getCurrentPositionAsync({}).then((location) =>
setPosition(location); setPosition(location)
}); );
}; };
useEffect(() => { useEffect(() => {
if (!position) return () => {}; if (!position) return () => {};
@ -219,29 +218,19 @@ export default function Menu({ getCurrentTrain }) {
<StatusbarDetect /> <StatusbarDetect />
<TitleBar /> <TitleBar />
<ScrollView <ScrollView
stickyHeaderIndices={[1, 3]}
ref={scrollRef} ref={scrollRef}
snapToStart={false} snapToStart={false}
snapToEnd={false} snapToEnd={false}
decelerationRate={"normal"} decelerationRate={"normal"}
onScroll={(d) => { onScroll={(d) => {
console.log(Object.keys(scrollRef.current));
const scrollY = d.nativeEvent.contentOffset.y + 100; const scrollY = d.nativeEvent.contentOffset.y + 100;
setMapsOpacity(scrollY < mapsSizeOffset); setMapsOpacity(scrollY < MapHeight);
}} }}
snapToOffsets={[mapsSizeOffset]} snapToOffsets={[MapHeight - 80]}
> >
<View style={{ position: "relative", height: 0 }}>
<MapView <MapView
ref={mapsRef} ref={mapsRef}
style={{ style={{ flex: 1, width: "100%", height: MapHeight }}
flex: 1,
width: "100%",
position: "absolute",
height:
(height / 100) * 60 + (((width / 100) * 80) / 20) * 9 + 60,
opacity: mapsOpacity ? 1 : 0,
}}
showsUserLocation={true} showsUserLocation={true}
loadingEnabled={true} loadingEnabled={true}
showsMyLocationButton={false} showsMyLocationButton={false}
@ -254,22 +243,9 @@ export default function Menu({ getCurrentTrain }) {
latitudeDelta: 1.8, //小さくなるほどズーム latitudeDelta: 1.8, //小さくなるほどズーム
longitudeDelta: 1.8, longitudeDelta: 1.8,
}} }}
onPress={() => { onPress={() => alert("地図をタップ")}
alert("地図をタップ"); />
}} <View style={{ width: "100%", height: 40, flexDirection: "row" }}>
></MapView>
</View>
<TopMenuButton show={mapsOpacity} />
<View style={{ height: mapsSizeOffset, position: "relative" }}>
<View
style={{
width: "100%",
position: "absolute",
bottom: 0,
flexDirection: "row",
display: mapsOpacity ? "flex" : "none",
}}
>
<TouchableOpacity <TouchableOpacity
style={{ style={{
flex: 1, flex: 1,
@ -281,8 +257,8 @@ export default function Menu({ getCurrentTrain }) {
borderRadius: 30, borderRadius: 30,
}} }}
disabled={!locationStatus} disabled={!locationStatus}
onPress={()=>{ onPress={() => {
if(!position) return; if (!position) return;
const { latitude, longitude } = position.coords; const { latitude, longitude } = position.coords;
mapsRef.current.animateToRegion( mapsRef.current.animateToRegion(
{ {
@ -320,7 +296,6 @@ export default function Menu({ getCurrentTrain }) {
padding: 5, padding: 5,
alignItems: "center", alignItems: "center",
flexDirection: "row", flexDirection: "row",
marginHorizontal: 5, marginHorizontal: 5,
borderRadius: 30, borderRadius: 30,
}} }}
@ -347,17 +322,8 @@ export default function Menu({ getCurrentTrain }) {
</Text> </Text>
</TouchableOpacity> </TouchableOpacity>
</View> </View>
<View {allStationData.length != 0 && originalStationList.length != 0 && (
style={{ <>
height: 0,
backgroundColor: "white",
position: "absolute",
top: mapsSizeOffset,
}}
/>
</View>
<></>
{originalStationList.length != 0 && allStationData.length != 0 && (
<View style={{ flex: 1, paddingTop: 10 }}> <View style={{ flex: 1, paddingTop: 10 }}>
<Carousel <Carousel
ref={carouselRef} ref={carouselRef}
@ -380,7 +346,7 @@ export default function Menu({ getCurrentTrain }) {
<View <View
style={{ style={{
backgroundColor: "#0000", backgroundColor: "#0000",
width: width, width,
flexDirection: "row", flexDirection: "row",
marginLeft: 0, marginLeft: 0,
marginRight: 0, marginRight: 0,
@ -432,10 +398,7 @@ export default function Menu({ getCurrentTrain }) {
})} })}
</View> </View>
</View> </View>
)} {allStationData[selectedCurrentStation] && (
{allStationData.length != 0 &&
originalStationList.length != 0 &&
allStationData[selectedCurrentStation] && (
<LED_vision <LED_vision
station={allStationData[selectedCurrentStation]} station={allStationData[selectedCurrentStation]}
getCurrentTrain={getCurrentTrain} getCurrentTrain={getCurrentTrain}
@ -443,156 +406,13 @@ export default function Menu({ getCurrentTrain }) {
openStationACFromEachTrainInfo={() => {}} openStationACFromEachTrainInfo={() => {}}
/> />
)} )}
</>
)}
<TopMenuButton />
<JRSTraInfoBox /> <JRSTraInfoBox />
<FixedContentBottom navigate={navigate} /> <FixedContentBottom navigate={navigate} />
</ScrollView> </ScrollView>
</View> </View>
); );
} }
const TopMenuButton = ({ show }) => {
const buttonList = [
{
backgroundColor: "#F89038",
icon: "train-car",
onPress: () =>
Linking.openURL("https://www.jr-shikoku.co.jp/01_trainbus/sp/"),
title: "駅・鉄道情報",
},
{
backgroundColor: "#EA4752",
icon: "google-spreadsheet",
onPress: () =>
Linking.openURL(
"https://www.jr-shikoku.co.jp/01_trainbus/jikoku/sp/#mainprice-box"
),
title: "運賃表",
},
{
backgroundColor: "#91C31F",
icon: "clipboard-list-outline",
onPress: () => Linking.openURL("https://www.jr-shikoku.co.jp/e5489/"),
title: "予約",
},
];
return (
<View style={{ flexDirection: "row", opacity: !show ? 1 : 0 }}>
{buttonList.map((d, index) => (
<UsefulBox
backgroundColor={d.backgroundColor}
icon={d.icon}
flex={1}
disable={show}
onPressButton={d.onPress}
key={index + d.icon}
>
{d.title}
</UsefulBox>
))}
</View>
);
};
const JRSTraInfoBox = () => {
const { getTime, delayData, loadingDelayData, setLoadingDelayData } =
useTrainDelayData();
const styles = {
touch: {
backgroundColor: "#0099CC",
borderRadius: 5,
margin: 10,
borderColor: "black",
borderWidth: 2,
overflow: "hidden",
},
scroll: {
backgroundColor: "#0099CC",
borderRadius: 5,
maxHeight: 300,
},
bottom: {
position: "absolute",
top: 250,
alignItems: "center",
width: "100%",
height: 50,
backgroundColor: "#007FCC88",
},
box: {
padding: 10,
backgroundColor: "white",
borderBottomLeftRadius: 5,
borderBottomRightRadius: 5,
},
};
return (
<TouchableOpacity
onPress={() => SheetManager.show("JRSTraInfo")}
style={styles.touch}
>
<ScrollView scrollEnabled={false} style={styles.scroll}>
<View
style={{ padding: 10, flexDirection: "row", alignItems: "center" }}
>
<Text style={{ fontSize: 30, fontWeight: "bold", color: "white" }}>
列車遅延速報EX
</Text>
<View style={{ flex: 1 }} />
<Text style={{ fontSize: 30, fontWeight: "bold", color: "white" }}>
{getTime
? getTime.toLocaleTimeString("ja-JP").split(":")[0] +
":" +
getTime.toLocaleTimeString("ja-JP").split(":")[1]
: NaN}
</Text>
<Ionicons
name="reload"
color="white"
size={30}
style={{ margin: 5 }}
onPress={() => {
setLoadingDelayData(true);
}}
/>
</View>
<View style={styles.box}>
{loadingDelayData ? (
<View style={{ alignItems: "center" }}>
<LottieView
autoPlay
loop
style={{ width: 150, height: 150, backgroundColor: "#fff" }}
source={require("./assets/51690-loading-diamonds.json")}
/>
</View>
) : delayData ? (
delayData.map((d, index, array) => {
let data = d.split(" ");
return (
<View
style={{ flexDirection: "row" }}
key={data[1] + "key" + index}
>
<Text style={{ flex: 15, fontSize: 18 }}>
{data[0].replace("\n", "")}
</Text>
<Text style={{ flex: 5, fontSize: 18 }}>{data[1]}</Text>
<Text style={{ flex: 6, fontSize: 18 }}>{data[3]}</Text>
</View>
);
})
) : (
<Text>現在5分以上の遅れはありません</Text>
)}
</View>
</ScrollView>
<View style={styles.bottom}>
<View style={{ flex: 1 }} />
<Text style={{ color: "white", fontWeight: "bold", fontSize: 20 }}>
詳細を見る
</Text>
<View style={{ flex: 1 }} />
</View>
</TouchableOpacity>
);
};