When MOCK_API_FEATURE_ENABLED is on, getCurrentTrain() now returns mock data instead of fetching from the n8n webhook or fallback API. - App.tsx: move TrainMenuProvider before CurrentTrainProvider so useTrainMenu() is available inside CurrentTrainProvider - useCurrentTrain: import useTrainMenu + MOCK_TRAIN_POSITIONS; getCurrentTrain() short-circuits to mock data when mockApiFeatureEnabled; added useEffect on mockApiFeatureEnabled to reload immediately on toggle Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
188 lines
5.9 KiB
TypeScript
188 lines
5.9 KiB
TypeScript
import React, { useEffect } from "react";
|
||
import {
|
||
IS_LOW_DENSITY,
|
||
DEX_SCALE,
|
||
useRealWindowDimensions,
|
||
} from "./utils/dexDimensionOverride";
|
||
import { Linking, Platform, UIManager, View } from "react-native";
|
||
import { GestureHandlerRootView } from "react-native-gesture-handler";
|
||
import "./utils/disableFontScaling"; // グローバルなフォントスケーリング無効化
|
||
import { AppContainer } from "./Apps";
|
||
import { UpdateAsync } from "./UpdateAsync";
|
||
import { LogBox } from "react-native";
|
||
import { FavoriteStationProvider } from "./stateBox/useFavoriteStation";
|
||
import { CurrentTrainProvider } from "./stateBox/useCurrentTrain";
|
||
import { AreaInfoProvider } from "./stateBox/useAreaInfo";
|
||
import { BusAndTrainDataProvider } from "./stateBox/useBusAndTrainData";
|
||
import { AllTrainDiagramProvider } from "./stateBox/useAllTrainDiagram";
|
||
import { SheetProvider, SheetManager } from "react-native-actions-sheet";
|
||
import "./components/ActionSheetComponents/sheets";
|
||
import { TrainDelayDataProvider } from "./stateBox/useTrainDelayData";
|
||
import { SafeAreaProvider } from "react-native-safe-area-context";
|
||
import { DeviceOrientationChangeProvider } from "./stateBox/useDeviceOrientationChange";
|
||
import { TrainMenuProvider } from "./stateBox/useTrainMenu";
|
||
import { buildProvidersTree } from "./lib/providerTreeProvider";
|
||
import { StationListProvider } from "./stateBox/useStationList";
|
||
import { NotificationProvider } from "./stateBox/useNotifications";
|
||
import { UserPositionProvider } from "./stateBox/useUserPosition";
|
||
import { rootNavigationRef, stackAwareNavigate } from "./lib/rootNavigation";
|
||
import { AppThemeProvider } from "./lib/theme";
|
||
import StatusbarDetect from "./StatusbarDetect";
|
||
|
||
LogBox.ignoreLogs([
|
||
"ViewPropTypes will be removed",
|
||
"ColorPropType will be removed",
|
||
]);
|
||
|
||
if (Platform.OS === "android") {
|
||
if (UIManager.setLayoutAnimationEnabledExperimental) {
|
||
UIManager.setLayoutAnimationEnabledExperimental(true);
|
||
}
|
||
}
|
||
|
||
export default function App() {
|
||
useEffect(() => {
|
||
UpdateAsync();
|
||
}, []);
|
||
|
||
useEffect(() => {
|
||
const openFelicaPage = (retryCount = 0) => {
|
||
if (!rootNavigationRef.isReady()) {
|
||
if (retryCount < 8) {
|
||
setTimeout(() => openFelicaPage(retryCount + 1), 250);
|
||
}
|
||
return;
|
||
}
|
||
|
||
stackAwareNavigate("topMenu", {
|
||
screen: "setting",
|
||
params: {
|
||
screen: "FelicaHistoryPage",
|
||
},
|
||
});
|
||
};
|
||
|
||
const navigateWhenReady = (
|
||
callback: () => void,
|
||
url: string,
|
||
retryCount = 0
|
||
) => {
|
||
if (!rootNavigationRef.isReady()) {
|
||
if (retryCount < 8) {
|
||
setTimeout(() => navigateWhenReady(callback, url, retryCount + 1), 250);
|
||
}
|
||
return;
|
||
}
|
||
callback();
|
||
};
|
||
|
||
const routeFromUrl = (url: string, retryCount = 0) => {
|
||
const normalized = (url || "").toLowerCase();
|
||
if (!normalized) return;
|
||
|
||
if (
|
||
normalized.includes("felicahistorypage") ||
|
||
normalized.includes("open/felica")
|
||
) {
|
||
navigateWhenReady(() => openFelicaPage(), url, retryCount);
|
||
} else if (normalized.includes("open/traininfo")) {
|
||
navigateWhenReady(() => {
|
||
stackAwareNavigate("topMenu", { screen: "menu" });
|
||
setTimeout(() => {
|
||
SheetManager.show("JRSTraInfo");
|
||
}, 450);
|
||
}, url, retryCount);
|
||
} else if (normalized.includes("open/operation")) {
|
||
navigateWhenReady(() => {
|
||
stackAwareNavigate("information");
|
||
}, url, retryCount);
|
||
} else if (normalized.includes("open/settings")) {
|
||
navigateWhenReady(() => {
|
||
stackAwareNavigate("topMenu", {
|
||
screen: "setting",
|
||
});
|
||
}, url, retryCount);
|
||
} else if (normalized.includes("open/topmenu")) {
|
||
navigateWhenReady(() => {
|
||
stackAwareNavigate("topMenu", {
|
||
screen: "menu",
|
||
});
|
||
}, url, retryCount);
|
||
} else if (normalized.includes("positions/apps")) {
|
||
navigateWhenReady(() => {
|
||
stackAwareNavigate("positions");
|
||
}, url, retryCount);
|
||
}
|
||
};
|
||
|
||
Linking.getInitialURL().then((url) => {
|
||
if (url) routeFromUrl(url);
|
||
});
|
||
|
||
const sub = Linking.addEventListener("url", ({ url }) => {
|
||
routeFromUrl(url);
|
||
});
|
||
|
||
return () => {
|
||
sub.remove();
|
||
};
|
||
}, []);
|
||
|
||
const ProviderTree = buildProvidersTree([
|
||
AllTrainDiagramProvider,
|
||
NotificationProvider,
|
||
UserPositionProvider,
|
||
StationListProvider,
|
||
FavoriteStationProvider,
|
||
TrainDelayDataProvider,
|
||
TrainMenuProvider, // CurrentTrainProvider より先に置くことで useTrainMenu が使える
|
||
CurrentTrainProvider,
|
||
AreaInfoProvider,
|
||
BusAndTrainDataProvider,
|
||
SheetProvider,
|
||
]);
|
||
return (
|
||
<AppThemeProvider>
|
||
<DeviceOrientationChangeProvider>
|
||
<SafeAreaProvider>
|
||
<StatusbarDetect />
|
||
<DensityScaleWrapper>
|
||
<GestureHandlerRootView style={{ flex: 1 }}>
|
||
<ProviderTree>
|
||
<AppContainer />
|
||
</ProviderTree>
|
||
</GestureHandlerRootView>
|
||
</DensityScaleWrapper>
|
||
</SafeAreaProvider>
|
||
</DeviceOrientationChangeProvider>
|
||
</AppThemeProvider>
|
||
);
|
||
}
|
||
|
||
/**
|
||
* 低密度ディスプレイ(DeX等)で全体を transform scale で拡大。
|
||
* Dimensions.get をパッチ済みなので、コンポーネントは内部サイズに合わせてレイアウトする。
|
||
*/
|
||
function DensityScaleWrapper({ children }: { children: React.ReactNode }) {
|
||
const { width, height } = useRealWindowDimensions();
|
||
|
||
if (!IS_LOW_DENSITY) {
|
||
return <>{children}</>;
|
||
}
|
||
|
||
return (
|
||
<View style={{ width, height, overflow: "hidden" }}>
|
||
<View
|
||
style={{
|
||
width: width / DEX_SCALE,
|
||
height: height / DEX_SCALE,
|
||
transform: [{ scale: DEX_SCALE }],
|
||
transformOrigin: "top left",
|
||
}}
|
||
>
|
||
{children}
|
||
</View>
|
||
</View>
|
||
);
|
||
}
|