メニューの路線別リストアップ機能を追加

This commit is contained in:
harukin-expo-dev-env 2025-07-07 11:48:46 +00:00
parent 6b39a3f723
commit 9478f2df8d
4 changed files with 128 additions and 45 deletions

View File

@ -7,6 +7,7 @@ import {
LayoutAnimation, LayoutAnimation,
TouchableOpacity, TouchableOpacity,
Text, Text,
ScrollView,
} from "react-native"; } from "react-native";
import Carousel, { ICarouselInstance } from "react-native-reanimated-carousel"; import Carousel, { ICarouselInstance } from "react-native-reanimated-carousel";
import { SheetManager } from "react-native-actions-sheet"; import { SheetManager } from "react-native-actions-sheet";
@ -19,11 +20,22 @@ export const CarouselBox = ({
setListIndex, setListIndex,
listIndex, listIndex,
navigate, navigate,
stationListMode stationListMode,
}) => { }) => {
const carouselRef = useRef<ICarouselInstance>(null); const carouselRef = useRef<ICarouselInstance>(null);
const { height, width } = useWindowDimensions(); const { height, width } = useWindowDimensions();
const [dotButton, setDotButton] = useState(false); const [dotButton, setDotButton] = useState(false);
const carouselBadgeScrollViewRef = useRef<ScrollView>(null);
useEffect(() => {
if (!carouselBadgeScrollViewRef.current) return;
const scrollToIndex = listIndex * (width / listUpStation.length) + 10;
console.log("scrollToIndex", scrollToIndex);
carouselBadgeScrollViewRef.current.scrollTo({
x: scrollToIndex,
animated: true,
});
}, [listIndex, dotButton, width, carouselBadgeScrollViewRef]);
const oPSign = () => { const oPSign = () => {
const payload = { const payload = {
currentStation: listUpStation[listIndex], currentStation: listUpStation[listIndex],
@ -98,7 +110,9 @@ export const CarouselBox = ({
}} }}
> >
<Text style={{ color: "#0099CC", fontSize: 20 }}> <Text style={{ color: "#0099CC", fontSize: 20 }}>
{stationListMode == "position" ? "現在地の近くに駅がありません。" : "お気に入りリストがありません。お気に入りの駅を追加しよう!"} {stationListMode == "position"
? "現在地の近くに駅がありません。"
: "お気に入りリストがありません。お気に入りの駅を追加しよう!"}
</Text> </Text>
</View> </View>
</TouchableOpacity> </TouchableOpacity>
@ -131,12 +145,23 @@ export const CarouselBox = ({
onSnapToItem={setListIndex} onSnapToItem={setListIndex}
renderItem={RenderItem} renderItem={RenderItem}
/> />
<View <ScrollView
style={{ horizontal
showsHorizontalScrollIndicator={false}
contentContainerStyle={{
flexDirection: "row", flexDirection: "row",
justifyContent: "center", justifyContent: "center",
alignContent: "center", alignContent: "center",
alignItems: "center", alignItems: "center",
paddingVertical: 2,
paddingHorizontal: 10,
minWidth: width,
}}
ref={(scrollViewRef) => {
// ScrollViewのrefを保存
if (scrollViewRef) {
carouselBadgeScrollViewRef.current = scrollViewRef;
}
}} }}
> >
{originalStationList && {originalStationList &&
@ -158,7 +183,7 @@ export const CarouselBox = ({
/> />
); );
})} })}
</View> </ScrollView>
</View> </View>
); );
}; };

View File

@ -23,9 +23,10 @@ export const CarouselTypeChanger = ({
setSelectedCurrentStation, setSelectedCurrentStation,
mapMode, mapMode,
setMapMode, setMapMode,
isSearchMode,
setisSearchMode,
}) => { }) => {
const tabBarHeight = useBottomTabBarHeight(); const tabBarHeight = useBottomTabBarHeight();
const [isSearchMode, setisSearchMode] = React.useState(false);
const { height, width } = useWindowDimensions(); const { height, width } = useWindowDimensions();
const returnToDefaultMode = () => { const returnToDefaultMode = () => {
LayoutAnimation.configureNext({ LayoutAnimation.configureNext({

View File

@ -10,53 +10,90 @@ import {
} from "react-native"; } from "react-native";
import Ionicons from "react-native-vector-icons/Ionicons"; import Ionicons from "react-native-vector-icons/Ionicons";
import { useWindowDimensions } from "react-native"; import { useWindowDimensions } from "react-native";
import lineColorList from "@/assets/originData/lineColorList";
import { lineList_LineWebID, stationIDPair } from "@/lib/getStationList";
export const SearchUnitBox = ({ isSearchMode, setisSearchMode }) => { export const SearchUnitBox = ({ isSearchMode, setisSearchMode }) => {
const { height, width } = useWindowDimensions(); const { height, width } = useWindowDimensions();
return ( return (
<> <>
<TouchableOpacity <TouchableOpacity
style={{ style={{
position: "absolute", position: "absolute",
bottom: isSearchMode ? 0 : 60, bottom: !!isSearchMode ? 0 : 60,
right: 0, right: 0,
padding: isSearchMode ? 5 : 10, padding: !!isSearchMode ? 5 : 10,
margin: isSearchMode ? 0 : 10, margin: !!isSearchMode ? 0 : 10,
backgroundColor: "#0099CC", backgroundColor: "#0099CC",
borderRadius: isSearchMode ? 5 : 50, borderRadius: !!isSearchMode ? 5 : 50,
width: isSearchMode ? width : 50, width: !!isSearchMode ? width : 50,
zIndex: 1000, zIndex: 1000,
}} }}
disabled={isSearchMode} disabled={!!isSearchMode}
onPress={() => { onPress={() => {
LayoutAnimation.configureNext({ LayoutAnimation.configureNext({
duration: 200, duration: 100,
update: { type: "easeInEaseOut", springDamping: 0.6 }, update: { type: "easeInEaseOut", springDamping: 0.6 },
}); });
setisSearchMode(true); setisSearchMode(true);
}} }}
> >
{!isSearchMode && <Ionicons name="search" size={30} color="white" />} {!isSearchMode && <Ionicons name="search" size={30} color="white" />}
{isSearchMode && ( {!!isSearchMode && (
<View style={{ backgroundColor: "#0099CC" }}> <View style={{ backgroundColor: "#0099CC" }}>
<Text
style={{ color: "white" }} <View style={{ flexDirection: "row", alignItems: "center" }}>
onPress={() => { <TouchableOpacity onPress={() => {
LayoutAnimation.configureNext({ LayoutAnimation.configureNext({
duration: 200, duration: 100,
update: { type: "easeInEaseOut", springDamping: 0.6 }, update: { type: "easeInEaseOut", springDamping: 0.6 },
}); });
setisSearchMode(false); setisSearchMode(false);
}} }}>
> <Ionicons
name="arrow-back"
</Text> size={20}
<View color="white"
style={{ marginRight: 10 }}
/>
</TouchableOpacity>
{Object.keys(lineList_LineWebID).map((d) => (
<TouchableOpacity
style={{
flex: 1,
backgroundColor: lineColorList[stationIDPair[lineList_LineWebID[d]]],
padding: 5,
marginHorizontal: 2,
borderRadius: 10,
borderColor: "white",
borderWidth: 1,
borderStyle: "solid",
alignItems: "center",
opacity: isSearchMode == stationIDPair[lineList_LineWebID[d]] ? 1 : !isSearchMode ? 1 : 0.5,
zIndex: 10,
}}
onPress={() => {
const id = stationIDPair[lineList_LineWebID[d]];
const s = isSearchMode == id ? undefined : id;
if (!s) return;
setisSearchMode(s);
}}
key={stationIDPair[lineList_LineWebID[d]]}
>
<Text
style={{ color: "white", fontWeight: "bold", fontSize: 20 }}
>
{stationIDPair[lineList_LineWebID[d]]}
</Text>
</TouchableOpacity>
))}
{/* <View
style={{ style={{
backgroundColor: "white", backgroundColor: "white",
borderRadius: 25, borderRadius: 25,
height: 30, height: 30,
paddingRight: 10, paddingRight: 10,
paddingLeft: 10, paddingLeft: 10,
flex: 1,
}} }}
> >
<TextInput <TextInput
@ -67,10 +104,11 @@ export const SearchUnitBox = ({ isSearchMode, setisSearchMode }) => {
//value={input} //value={input}
style={{ flex: 1 }} style={{ flex: 1 }}
/> />
</View> */}
</View> </View>
</View> </View>
)} )}
</TouchableOpacity> </TouchableOpacity>
</> </>
); );
}; };

29
menu.js
View File

@ -19,7 +19,7 @@ import LED_vision from "./components/発車時刻表/LED_vidion";
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 { lineList } from "./lib/getStationList"; import { lineList, stationIDPair } from "./lib/getStationList";
import { useFavoriteStation } from "./stateBox/useFavoriteStation"; import { useFavoriteStation } from "./stateBox/useFavoriteStation";
import { useNavigation } from "@react-navigation/native"; import { useNavigation } from "@react-navigation/native";
import { useStationList } from "./stateBox/useStationList"; import { useStationList } from "./stateBox/useStationList";
@ -32,6 +32,7 @@ import { CarouselBox } from "./components/Menu/Carousel/CarouselBox";
import { CarouselTypeChanger } from "./components/Menu/Carousel/CarouselTypeChanger"; import { CarouselTypeChanger } from "./components/Menu/Carousel/CarouselTypeChanger";
import { useUserPosition } from "./stateBox/useUserPosition"; import { useUserPosition } from "./stateBox/useUserPosition";
import { AS } from "./storageControl"; import { AS } from "./storageControl";
import { lineList_LineWebID } from "./lib/getStationList";
import { Ionicons } from "@expo/vector-icons"; import { Ionicons } from "@expo/vector-icons";
import { SearchUnitBox } from "./components/Menu/RailScope/SearchUnitBox"; import { SearchUnitBox } from "./components/Menu/RailScope/SearchUnitBox";
configureReanimatedLogger({ configureReanimatedLogger({
@ -171,13 +172,26 @@ export default function Menu(props) {
const [listIndex, setListIndex] = useState(0); const [listIndex, setListIndex] = useState(0);
const [listUpStation, setListUpStation] = useState([]); const [listUpStation, setListUpStation] = useState([]);
const [isSearchMode, setisSearchMode] = useState(false);
useEffect(() => { useEffect(() => {
if (stationListMode == "position") { if (!!isSearchMode) {
const returnData = [];
Object.keys(lineList_LineWebID).forEach((d, indexBase) => {
originalStationList[d].forEach((D, index) => {
if (isSearchMode && isSearchMode != stationIDPair[lineList_LineWebID[d]]) return;
const latlng = [D.lat, D.lng];
if (latlng.length == 0) return null;
returnData.push([D]);
});
});
setListUpStation(returnData);
}
else if (stationListMode == "position") {
setListUpStation(nearPositionStation.filter((d) => d != undefined)); setListUpStation(nearPositionStation.filter((d) => d != undefined));
} else { } else {
setListUpStation(favoriteStation.filter((d) => d != undefined)); setListUpStation(favoriteStation.filter((d) => d != undefined));
} }
}, [nearPositionStation, favoriteStation, stationListMode]); }, [nearPositionStation, favoriteStation, stationListMode, isSearchMode]);
useEffect(() => { useEffect(() => {
if (listUpStation.length == 0) { if (listUpStation.length == 0) {
setListIndex(0); setListIndex(0);
@ -325,15 +339,18 @@ export default function Menu(props) {
{...{ {...{
locationStatus, locationStatus,
position, position,
mapsRef,scrollRef, mapsRef,
scrollRef,
stationListMode, stationListMode,
setStationListMode, setStationListMode,
setSelectedCurrentStation: setListIndex, setSelectedCurrentStation: setListIndex,
mapMode, mapMode,
setMapMode, setMapMode,
isSearchMode,
setisSearchMode,
}} }}
/> />
)} )}
{originalStationList.length != 0 && ( {originalStationList.length != 0 && (
<> <>
@ -373,6 +390,8 @@ export default function Menu(props) {
setSelectedCurrentStation: setListIndex, setSelectedCurrentStation: setListIndex,
mapMode, mapMode,
setMapMode, setMapMode,
isSearchMode,
setisSearchMode,
}} }}
/> />
)} )}