feat: add opt-in service formation display to train details
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
import { useServiceStates } from "@/stateBox/useCurrentTrain";
|
||||
import { formationText, serviceStateText } from "@/lib/serviceState/display";
|
||||
import React, { FC, useMemo } from "react";
|
||||
import { Text, View, TextStyle, TouchableOpacity } from "react-native";
|
||||
import { SheetManager } from "react-native-actions-sheet";
|
||||
@@ -52,6 +54,9 @@ export const HeaderText: FC<Props> = ({
|
||||
const { fixed } = useThemeColors();
|
||||
const { fontScale } = useResponsive();
|
||||
const { iconSetting } = useTrainMenu();
|
||||
const { serviceStates, available, getFormation } = useServiceStates();
|
||||
const serviceState = serviceStates.find(state => state.train_id === trainNum);
|
||||
const shadowText = available ? serviceState ? serviceStateText(serviceState) : formationText(getFormation(trainNum)) : null;
|
||||
const { allCustomTrainData } = useCustomTrainData();
|
||||
const { getTodayOperationByTrainId } = useOperationLogs();
|
||||
const { expoPushToken } = useNotification();
|
||||
@@ -222,6 +227,7 @@ export const HeaderText: FC<Props> = ({
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<View
|
||||
style={{
|
||||
padding: 10,
|
||||
@@ -233,14 +239,14 @@ export const HeaderText: FC<Props> = ({
|
||||
scrollRef.current?.scrollTo({ y: 0, animated: true })
|
||||
}
|
||||
>
|
||||
<TrainIconStatus
|
||||
{!shadowText && <TrainIconStatus
|
||||
trainNum={trainNum}
|
||||
navigate={navigate}
|
||||
from={from}
|
||||
todayOperation={todayOperation}
|
||||
direction={iconTrainDirection}
|
||||
iconDisplayMode={iconDisplayMode}
|
||||
/>
|
||||
/>}
|
||||
|
||||
<View
|
||||
style={{
|
||||
@@ -343,5 +349,9 @@ export const HeaderText: FC<Props> = ({
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
{shadowText && <View style={{ paddingHorizontal: 10, paddingBottom: 10 }}>
|
||||
<Text style={{ color: fixed.textOnPrimary, fontSize: fontScale(14) }}>{shadowText}</Text>
|
||||
</View>}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -42,7 +42,7 @@ export const ResearchToolsSettings = () => {
|
||||
})
|
||||
.catch(() => {});
|
||||
}, []);
|
||||
const { updatePermission, mockApiFeatureEnabled, setMockApiFeatureEnabled } =
|
||||
const { updatePermission, mockApiFeatureEnabled, setMockApiFeatureEnabled, serviceStateShadowEnabled, setServiceStateShadowEnabled } =
|
||||
useTrainMenu();
|
||||
const {
|
||||
recorderState,
|
||||
@@ -204,6 +204,14 @@ export const ResearchToolsSettings = () => {
|
||||
</View>
|
||||
) : (
|
||||
<>
|
||||
<View style={[styles.debugSection, { backgroundColor: colors.surface, borderColor: colors.borderSecondary }]}>
|
||||
<Text style={[styles.debugTitle, { color: colors.textPrimary }]}>区間ごとの編成表示(検証)</Text>
|
||||
<Text style={[styles.debugDescription, { color: colors.textSecondary }]}>列車詳細と走行位置に、その区間の編成を表示します。</Text>
|
||||
<View style={styles.switchRow}>
|
||||
<Text style={{ color: colors.textPrimary }}>区間ごとの編成表示</Text>
|
||||
<Switch value={serviceStateShadowEnabled} onValueChange={setServiceStateShadowEnabled} color={fixed.primary} />
|
||||
</View>
|
||||
</View>
|
||||
<View
|
||||
style={[
|
||||
styles.debugSection,
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
import type { AssignedComponent, Formation, ServiceState } from "./types";
|
||||
|
||||
export function componentsText(components: readonly AssignedComponent[]): string {
|
||||
return [...components].sort((a, b) => a.order - b.order)
|
||||
.map(c => c.unit_ids?.length ? c.unit_ids.join(" + ") : "不明").join(" + ") || "不明";
|
||||
}
|
||||
|
||||
export function serviceStateText(state: ServiceState): string | null {
|
||||
if (state.status === "unsupported") return null;
|
||||
const status = state.status === "partial" ? "一部不明" : state.status === "transition" ? "増結・分割・交換作業中の可能性" : "";
|
||||
return [componentsText(state.components), status].filter(Boolean).join(" / ");
|
||||
}
|
||||
|
||||
export function formationText(formation: Formation): string | null {
|
||||
if (!formation.sections.length) return null;
|
||||
const sections = [...new Set(formation.sections.map(s => componentsText(s.components)))];
|
||||
return `本日の編成: ${sections.join(" → ")} / 現在位置: 取得できません`;
|
||||
}
|
||||
Reference in New Issue
Block a user