Files
jrshikoku/menu.js
2025-05-06 16:27:42 +00:00

344 lines
11 KiB
JavaScript

import React, { useRef, useState, useEffect } from "react";
import {
Platform,
View,
ScrollView,
useWindowDimensions,
LayoutAnimation,
} from "react-native";
import Constants from "expo-constants";
import {
configureReanimatedLogger,
ReanimatedLogLevel,
} from "react-native-reanimated";
import StatusbarDetect from "./StatusbarDetect";
import LED_vision from "./components/発車時刻表/LED_vidion";
import { TitleBar } from "./components/Menu/TitleBar";
import { FixedContentBottom } from "./components/Menu/FixedContentBottom";
import { lineList } from "./lib/getStationList";
import { useFavoriteStation } from "./stateBox/useFavoriteStation";
import { useNavigation } from "@react-navigation/native";
import { useStationList } from "./stateBox/useStationList";
import { TopMenuButton } from "@/components/Menu/TopMenuButton";
import { JRSTraInfoBox } from "@/components/Menu/JRSTraInfoBox";
import MapView, { Marker } from "react-native-maps";
import { useSafeAreaInsets } from "react-native-safe-area-context";
import { useBottomTabBarHeight } from "@react-navigation/bottom-tabs";
import { CarouselBox } from "./components/Menu/Carousel/CarouselBox";
import { CarouselTypeChanger } from "./components/Menu/Carousel/CarouselTypeChanger";
import { useUserPosition } from "./stateBox/useUserPosition";
import { AS } from "./storageControl";
configureReanimatedLogger({
level: ReanimatedLogLevel.error, // Set the log level to error
strict: true, // Reanimated runs in strict mode by default
});
export default function Menu({
scrollRef,
mapHeight,
MapFullHeight,
mapMode,
setMapMode,
}) {
const { navigate, addListener, isFocused } = useNavigation();
const { favoriteStation } = useFavoriteStation();
const { originalStationList } = useStationList();
const { height, width } = useWindowDimensions();
const { bottom, left, right, top } = useSafeAreaInsets();
const tabBarHeight = useBottomTabBarHeight();
const [stationListMode, setStationListMode] = useState(
/*<"position"|"favorite">*/ "position"
);
useEffect(()=>{
AS.getItem("stationListMode").then((res) => {
setStationListMode(res);
}).catch((e) => {
// AS.setItem("stationListMode", "position");
});
}, []);
const mapsRef = useRef(null);
const returnToTop = (bool = true) => {
scrollRef.current.scrollTo({
y: mapHeight > 80 ? mapHeight - 80 : 0,
animated: bool,
});
};
const goToMap = () => {
scrollRef.current.scrollTo({
y: 0,
animated: true,
});
};
useEffect(() => {
setTimeout(() => {
returnToTop(false);
}, 10);
}, [mapHeight]);
const [scrollStartPosition, setScrollStartPosition] = useState(0);
const onScrollBeginDrag = (e) => {
LayoutAnimation.configureNext({
duration: 300,
create: {
type: LayoutAnimation.Types.easeInEaseOut,
property: LayoutAnimation.Properties.opacity,
},
update: {
type: LayoutAnimation.Types.easeInEaseOut,
property: LayoutAnimation.Properties.opacity,
},
});
setScrollStartPosition(e.nativeEvent.contentOffset.y);
setMapMode(false);
};
//現在地基準の駅名標リストアップ機能
const { position, locationStatus } = useUserPosition();
useEffect(() => {
if (!position) return () => {};
makeCurrentStation(position);
}, [position, stationListMode]);
const makeCurrentStation = (location) => {
if (!originalStationList) return () => {};
const findStationEachLine = (selectLine) => {
const searchArea = 0.12;
const _calcDistance = (from, to) => {
let lat = Math.abs(from.lat - to.lat);
let lng = Math.abs(from.lng - to.lng);
return Math.sqrt(lat * lat + lng * lng);
};
let NearStation = selectLine.filter(
(d) =>
_calcDistance(d, {
lat: location.coords.latitude,
lng: location.coords.longitude,
}) < searchArea
);
//NearStationを距離の近い順にソート
NearStation.sort((a, b) => {
return (
_calcDistance(a, {
lat: location.coords.latitude,
lng: location.coords.longitude,
}) -
_calcDistance(b, {
lat: location.coords.latitude,
lng: location.coords.longitude,
})
);
});
return NearStation;
};
let _stList = lineList
.map((d) => findStationEachLine(originalStationList[d]))
.filter((d) => d.length > 0)
.reduce((pre, current) => {
pre.push(...current);
return pre;
}, []);
if (_stList.length == 0) setNearPositionStation([]);
else {
let returnData = [];
_stList.forEach((d, index, array) => {
const stationName = d.Station_JP;
if (returnData.findIndex((d) => d[0].Station_JP == stationName) != -1) return;
returnData.push(array.filter((d2) => d2.Station_JP == stationName));
});
setNearPositionStation(returnData);
}
};
const [nearPositionStation, setNearPositionStation] = useState([]); //第三要素
const [listIndex, setListIndex] = useState(0);
const [listUpStation, setListUpStation] = useState([]);
useEffect(() => {
if (stationListMode == "position") {
setListUpStation(nearPositionStation.filter((d) => d != undefined));
} else {
setListUpStation(favoriteStation.filter((d) => d != undefined));
}
}, [nearPositionStation, favoriteStation, stationListMode]);
useEffect(() => {
if (listUpStation.length == 0) {
setListIndex(0);
return;
}
if (listUpStation[listIndex] == undefined) {
const count = listIndex - 1;
setMapMode(false);
setListIndex(count);
}
}, [listIndex, nearPositionStation, listUpStation]);
useEffect(() => {
if (originalStationList == undefined) return;
if (listUpStation.length == 0) return;
if (listUpStation[listIndex] == undefined) return;
const { lat, lng } = listUpStation[listIndex][0];
const mapRegion = {
latitude: lat,
longitude: lng,
latitudeDelta: 0.05,
longitudeDelta: 0.05,
};
if (mapMode) return;
mapsRef.current.animateToRegion(mapRegion, 1000);
}, [listIndex, nearPositionStation, listUpStation, mapsRef]);
return (
<View
style={{
height: "100%",
backgroundColor: "white",
paddingTop: Platform.OS == "ios" ? Constants.statusBarHeight : 0,
}}
>
<StatusbarDetect />
<TitleBar />
<ScrollView
ref={scrollRef}
snapToStart={false}
snapToEnd={false}
decelerationRate={"normal"}
snapToOffsets={[mapHeight - 80]}
onScrollBeginDrag={onScrollBeginDrag}
onScrollEndDrag={(e) => {
console.log(e.nativeEvent.velocity);
if (e.nativeEvent.contentOffset.y < mapHeight - 80) {
if (scrollStartPosition > e.nativeEvent.contentOffset.y) {
goToMap();
} else {
returnToTop();
}
}
}}
>
<MapView
ref={mapsRef}
style={{ width: "100%", height: mapMode ? MapFullHeight : mapHeight }}
showsUserLocation={true}
loadingEnabled={true}
showsMyLocationButton={false}
moveOnMarkerPress={false}
showsCompass={false}
//provider={PROVIDER_GOOGLE}
initialRegion={{
latitude: 33.774519,
longitude: 133.533306,
latitudeDelta: 1.8, //小さくなるほどズーム
longitudeDelta: 1.8,
}}
onTouchStart={() => {
LayoutAnimation.configureNext({
duration: 300,
create: {
type: LayoutAnimation.Types.easeInEaseOut,
property: LayoutAnimation.Properties.opacity,
},
update: {
type: LayoutAnimation.Types.easeInEaseOut,
property: LayoutAnimation.Properties.opacity,
},
});
setMapMode(true);
goToMap();
}}
>
{listUpStation.map(([{ lat, lng, StationNumber }], index) => (
<Marker
key={index + StationNumber}
coordinate={{
latitude: parseFloat(lat),
longitude: parseFloat(lng),
}}
image={require("@/assets/reccha-small.png")}
onPress={() => {
setMapMode(false);
setListIndex(index);
if (mapsRef.current) {
mapsRef.current.animateToRegion(
{
latitude: parseFloat(lat),
longitude: parseFloat(lng),
latitudeDelta: 0.05,
longitudeDelta: 0.05,
},
1000
);
}
LayoutAnimation.configureNext({
duration: 300,
create: {
type: LayoutAnimation.Types.easeInEaseOut,
property: LayoutAnimation.Properties.opacity,
},
update: {
type: LayoutAnimation.Types.easeInEaseOut,
property: LayoutAnimation.Properties.opacity,
},
});
returnToTop();
}}
/>
))}
</MapView>
{!mapMode && (
<CarouselTypeChanger
{...{
locationStatus,
position,
mapsRef,
stationListMode,
setStationListMode,
setSelectedCurrentStation: setListIndex,
mapMode,
setMapMode,
}}
/>
)}
{listUpStation.length != 0 && originalStationList.length != 0 && (
<>
<CarouselBox
{...{
originalStationList,
listUpStation,
nearPositionStation,
setListIndex,
listIndex,
navigate,
}}
/>
{listUpStation[listIndex] && (
<LED_vision
station={listUpStation[listIndex]}
navigate={navigate}
openStationACFromEachTrainInfo={() => {}}
/>
)}
</>
)}
<TopMenuButton />
<JRSTraInfoBox />
<FixedContentBottom navigate={navigate} />
</ScrollView>
{mapMode && (
<CarouselTypeChanger
{...{
locationStatus,
position,
mapsRef,
stationListMode,
setStationListMode,
setSelectedCurrentStation: setListIndex,
mapMode,
setMapMode,
}}
/>
)}
</View>
);
}