From 88fe4bba430f0e06442b442fac44b93d783a5947 Mon Sep 17 00:00:00 2001 From: Tsubasa SEKIGUCHI Date: Thu, 3 Sep 2026 01:02:29 +0900 Subject: [PATCH 1/2] =?UTF-8?q?LED=E3=83=86=E3=83=BC=E3=83=9E=E9=81=B8?= =?UTF-8?q?=E6=8A=9E=E4=B8=AD=E3=81=A7=E3=82=82=E3=83=9D=E3=83=BC=E3=83=88?= =?UTF-8?q?=E3=83=AC=E3=83=BC=E3=83=88=E3=83=A2=E3=83=BC=E3=83=89=E3=81=AE?= =?UTF-8?q?=E8=B5=B0=E8=A1=8C=E7=94=BB=E9=9D=A2=E3=82=92=E3=83=80=E3=83=BC?= =?UTF-8?q?=E3=82=AF=E3=83=A2=E3=83=BC=E3=83=89=E3=81=AE=E9=85=8D=E8=89=B2?= =?UTF-8?q?=E3=81=AB=E8=BF=BD=E5=BE=93=E3=81=95=E3=81=9B=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Permitted.tsx | 4 ++-- src/components/PortraitMain.test.tsx | 31 ++++++++++++++++++++++++++++ src/components/PortraitMain.tsx | 9 ++++---- src/screens/Licenses.tsx | 4 ++-- src/store/atoms/colorScheme.test.ts | 8 +++---- src/store/atoms/colorScheme.ts | 14 ++++++++----- src/utils/actionSheetColors.ts | 2 +- 7 files changed, 54 insertions(+), 18 deletions(-) diff --git a/src/components/Permitted.tsx b/src/components/Permitted.tsx index 4f2ef62fd..a34cf4d74 100644 --- a/src/components/Permitted.tsx +++ b/src/components/Permitted.tsx @@ -15,7 +15,7 @@ import { Linking, Platform, StyleSheet, View } from 'react-native'; import { LongPressGestureHandler, State } from 'react-native-gesture-handler'; import Share from 'react-native-share'; import ViewShot, { type ViewShotRef } from 'react-native-view-shot'; -import { overlayAppColorsAtom } from '~/store/atoms/colorScheme'; +import { resolvedAppColorsAtom } from '~/store/atoms/colorScheme'; import reportModalVisibleAtom from '~/store/atoms/reportModal'; import tuningState from '~/store/atoms/tuning'; import { getActionSheetColorOptions } from '~/utils/actionSheetColors'; @@ -139,7 +139,7 @@ const PermittedLayout: React.FC = ({ children }: Props) => { // アクションシートは車内再現(走行画面)とは別レイヤーの一時的なUIなので、 // 走行画面から開いた場合も配色設定に追従させる。走行画面はProviderの // 外側にあるため、モーダル本体と同じくatomを直接購読する。 - const actionSheetColors = useAtomValue(overlayAppColorsAtom); + const actionSheetColors = useAtomValue(resolvedAppColorsAtom); const { sendReport, descriptionLowerLimit } = useFeedback(user); const { warningInfo, clearWarningInfo } = useWarningInfo(); const { diff --git a/src/components/PortraitMain.test.tsx b/src/components/PortraitMain.test.tsx index 88c848319..2135cdf84 100644 --- a/src/components/PortraitMain.test.tsx +++ b/src/components/PortraitMain.test.tsx @@ -16,6 +16,7 @@ import { useTransferTargetStation, } from '~/hooks'; import { COLOR_SCHEME_PREFERENCE } from '~/models/ColorScheme'; +import { THEME_PREFERENCE, type ThemePreference } from '~/models/Theme'; import { colorSchemePreferenceAtom } from '~/store/atoms/colorScheme'; import { bottomStateAtom } from '~/store/atoms/navigation'; import { @@ -23,6 +24,7 @@ import { selectedDirectionAtom, stationsAtom, } from '~/store/atoms/station'; +import { themePreferenceAtom } from '~/store/atoms/theme'; import { translate } from '~/translation'; import { RFValue } from '~/utils/rfValue'; import PortraitMain from './PortraitMain'; @@ -126,6 +128,7 @@ const renderWithStations = ( arrived = true, currentStation = stations[0], colorScheme = COLOR_SCHEME_PREFERENCE.LIGHT, + themePreference, bottomState = 'LINE' as const, direction = 'INBOUND' as const, transferStation, @@ -135,6 +138,7 @@ const renderWithStations = ( arrived?: boolean; currentStation?: Station; colorScheme?: (typeof COLOR_SCHEME_PREFERENCE)[keyof typeof COLOR_SCHEME_PREFERENCE]; + themePreference?: ThemePreference; bottomState?: 'LINE' | 'TRANSFER' | 'TYPE_CHANGE'; direction?: 'INBOUND' | 'OUTBOUND'; transferStation?: Station; @@ -145,6 +149,9 @@ const renderWithStations = ( const store = createStore(); // 端末のダークモード状態に左右されないよう、配色は常に明示して固定する store.set(colorSchemePreferenceAtom, colorScheme); + if (themePreference) { + store.set(themePreferenceAtom, themePreference); + } // 全駅表示。非環状線の INBOUND は反転しないので渡した順がそのまま表示順になる。 store.set(stationsAtom, stations); store.set(selectedDirectionAtom, direction); @@ -565,6 +572,30 @@ describe('PortraitMain', () => { ).toBe(DARK_APP_COLORS.text); }); + // ポートレートは路線テーマに依存しないレイアウトで電光掲示板風の配色を持たないため、 + // 電光掲示板風テーマ選択中でも配色設定のダークがそのまま効く + it('電光掲示板風テーマ選択中でもダーク設定ならダークのトークンを使う', () => { + const { getByTestId } = renderWithStations( + [buildStation(1, '品川', StopCondition.All, 'JY-25')], + { + colorScheme: COLOR_SCHEME_PREFERENCE.DARK, + themePreference: THEME_PREFERENCE.LED, + } + ); + + expect( + StyleSheet.flatten(getByTestId('portrait-root').props.style) + .backgroundColor + ).toBe(DARK_APP_COLORS.background); + expect( + StyleSheet.flatten(getByTestId('portrait-station-card').props.style) + .backgroundColor + ).toBe(DARK_APP_COLORS.card); + expect( + StyleSheet.flatten(getByTestId('portrait-station-name').props.style).color + ).toBe(DARK_APP_COLORS.text); + }); + it('ダークでは沈まないよう路線色の明度を上げた色で線路を描く', () => { const { getByTestId } = renderWithStations( [buildStation(1, '品川', StopCondition.All, 'JY-25')], diff --git a/src/components/PortraitMain.tsx b/src/components/PortraitMain.tsx index a8d797c99..7e418c6c7 100644 --- a/src/components/PortraitMain.tsx +++ b/src/components/PortraitMain.tsx @@ -65,7 +65,7 @@ import { useTransferStationNumbers, useTransferTargetStation, } from '~/hooks'; -import { appColorsAtom } from '~/store/atoms/colorScheme'; +import { resolvedAppColorsAtom } from '~/store/atoms/colorScheme'; import { bottomStateAtom, enabledLanguagesAtom, @@ -91,8 +91,9 @@ import Typography from './Typography'; // 走行画面は AppColorsProvider の外側で描画されるため useAppColors() は常に // ライトの値を返す。ポートレートは配色設定に追従させたいので atom を直接読む。 -// 電光掲示板風テーマ選択中は appColorsAtom がライトを返すので、従来どおりの -// 見た目のまま保たれる。 +// appColorsAtom は電光掲示板風テーマ選択中にライトを返すが、この画面は路線テーマに +// 依存しないレイアウトで電光掲示板風の配色を持たないため、そちらではなく +// 上書きを受けない resolvedAppColorsAtom を読む。 const FALLBACK_ACCENT = '#888888'; // 通過駅の駅名・記号用。停車駅(secondaryText)よりさらに弱くして @@ -1353,7 +1354,7 @@ const PortraitMain: React.FC = ({ onPress, onTransferPress }) => { const topInset = isTablet ? Math.max(insets.top, STOP_LIST_PADDING_V + insets.bottom) : insets.top; - const colors = useAtomValue(appColorsAtom); + const colors = useAtomValue(resolvedAppColorsAtom); const commonData = useHeaderCommonData(); const allStations = useAtomValue(stationsAtom); const selectedDirection = useAtomValue(selectedDirectionAtom); diff --git a/src/screens/Licenses.tsx b/src/screens/Licenses.tsx index 813be82dd..f3c392571 100644 --- a/src/screens/Licenses.tsx +++ b/src/screens/Licenses.tsx @@ -15,7 +15,7 @@ import FooterTabBar from '~/components/FooterTabBar'; import { SettingsHeader } from '~/components/SettingsHeader'; import Typography from '~/components/Typography'; import { useAppColors } from '~/providers/AppColorsProvider'; -import { overlayAppColorsAtom } from '~/store/atoms/colorScheme'; +import { resolvedAppColorsAtom } from '~/store/atoms/colorScheme'; import { isLEDThemeAtom } from '~/store/atoms/theme'; import { translate } from '~/translation'; import { getActionSheetColorOptions } from '~/utils/actionSheetColors'; @@ -157,7 +157,7 @@ const Licenses: React.FC = () => { const colors = useAppColors(); // アクションシートはOS側のレイヤーに描かれるため、電光掲示板風テーマ中も // 配色設定に追従させる。詳細は getActionSheetColorOptions のコメントを参照 - const actionSheetColors = useAtomValue(overlayAppColorsAtom); + const actionSheetColors = useAtomValue(resolvedAppColorsAtom); const navigation = useNavigation(); const { showActionSheetWithOptions } = useActionSheet(); diff --git a/src/store/atoms/colorScheme.test.ts b/src/store/atoms/colorScheme.test.ts index 274faa44f..cbc8901f7 100644 --- a/src/store/atoms/colorScheme.test.ts +++ b/src/store/atoms/colorScheme.test.ts @@ -7,7 +7,7 @@ import { appColorsAtom, colorSchemePreferenceAtom, isDarkColorSchemeAtom, - overlayAppColorsAtom, + resolvedAppColorsAtom, resolvedColorSchemeAtom, systemColorSchemeAtom, } from './colorScheme'; @@ -60,17 +60,17 @@ describe('colorScheme atoms', () => { // アクションシートなどOS側のレイヤーに描かれるUIは、電光掲示板風テーマの // 配色を持ちようがないため設定値をそのまま反映する - it('overlayAppColorsAtomは電光掲示板風テーマでも配色設定に追従する', () => { + it('resolvedAppColorsAtomは電光掲示板風テーマでも配色設定に追従する', () => { const store = createStore(); store.set(themePreferenceAtom, THEME_PREFERENCE.LED); store.set(colorSchemePreferenceAtom, COLOR_SCHEME_PREFERENCE.DARK); - expect(store.get(overlayAppColorsAtom)).toBe(DARK_APP_COLORS); + expect(store.get(resolvedAppColorsAtom)).toBe(DARK_APP_COLORS); // 画面本体側は従来どおりライトのまま expect(store.get(appColorsAtom)).toBe(LIGHT_APP_COLORS); store.set(colorSchemePreferenceAtom, COLOR_SCHEME_PREFERENCE.LIGHT); - expect(store.get(overlayAppColorsAtom)).toBe(LIGHT_APP_COLORS); + expect(store.get(resolvedAppColorsAtom)).toBe(LIGHT_APP_COLORS); }); it('電光掲示板風テーマ選択中は端末がダークでもライトのパレットを返す', () => { diff --git a/src/store/atoms/colorScheme.ts b/src/store/atoms/colorScheme.ts index 5c8e2f92e..6296f5716 100644 --- a/src/store/atoms/colorScheme.ts +++ b/src/store/atoms/colorScheme.ts @@ -67,13 +67,17 @@ export const appColorsAtom = atom((get) => { }); /** - * 電光掲示板風テーマの有無を無視した配色。 + * 電光掲示板風テーマの上書きを受けない配色。 * - * アクションシートのように OS 側のレイヤーへ描かれ、電光掲示板風テーマの配色を - * 持ちようがない UI で使う。ここだけ配色設定に追従しないと、他がダークなのに - * シートだけ明るいという不具合に見えるため、テーマではなく設定値をそのまま反映する。 + * 電光掲示板風テーマの配色を持ちようがない UI で使う。次の 2 種類がある。 + * + * - アクションシートのように OS 側のレイヤーへ描かれるもの + * - ポートレートモードの走行画面のように、路線テーマに依存しないレイアウト + * + * ここまで `appColorsAtom` に合わせてしまうと、他がダークなのにその部分だけ + * 明るいという不具合に見えるため、テーマではなく設定値をそのまま反映する。 */ -export const overlayAppColorsAtom = atom( +export const resolvedAppColorsAtom = atom( (get) => APP_COLORS[get(resolvedColorSchemeAtom)] ); diff --git a/src/utils/actionSheetColors.ts b/src/utils/actionSheetColors.ts index 4ba5e5921..ef7a06a2b 100644 --- a/src/utils/actionSheetColors.ts +++ b/src/utils/actionSheetColors.ts @@ -15,7 +15,7 @@ import type { AppColors } from '~/constants/colorScheme'; * * アクションシートは OS 側のレイヤーに描かれ電光掲示板風テーマの配色を持ち * ようがないため、ここだけは電光掲示板風テーマでも配色設定に追従させる - * (`overlayAppColorsAtom` を渡す)。追従しないと他がダークなのにシートだけ + * (`resolvedAppColorsAtom` を渡す)。追従しないと他がダークなのにシートだけ * 明るいという不具合に見えてしまう。 */ export const getActionSheetColorOptions = ( From d246232ad24de935ce76695e69710cbf4610fe86 Mon Sep 17 00:00:00 2001 From: Tsubasa SEKIGUCHI Date: Thu, 3 Sep 2026 01:10:04 +0900 Subject: [PATCH 2/2] =?UTF-8?q?=E5=A4=96=E8=A6=B3=E8=A8=AD=E5=AE=9A?= =?UTF-8?q?=E3=81=AE=E8=AA=AC=E6=98=8E=E6=96=87=E3=82=92=E3=83=9D=E3=83=BC?= =?UTF-8?q?=E3=83=88=E3=83=AC=E3=83=BC=E3=83=88=E3=83=A2=E3=83=BC=E3=83=89?= =?UTF-8?q?=E3=81=8C=E3=83=80=E3=83=BC=E3=82=AF=E3=81=AB=E8=BF=BD=E5=BE=93?= =?UTF-8?q?=E3=81=99=E3=82=8B=E4=BE=8B=E5=A4=96=E3=81=AB=E5=90=88=E3=82=8F?= =?UTF-8?q?=E3=81=9B=E3=81=A6=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/translations/en.json | 2 +- assets/translations/ja.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/assets/translations/en.json b/assets/translations/en.json index fdd5af7a9..e2c07f154 100644 --- a/assets/translations/en.json +++ b/assets/translations/en.json @@ -54,7 +54,7 @@ "colorSchemeAuto": "Auto (follow system)", "colorSchemeLight": "Light", "colorSchemeDark": "Dark", - "colorSchemeDescription": "Changes the colors of screens such as settings and line selection. \"Auto\" follows your device's dark mode setting. The screen shown while riding keeps the colors of the selected theme, except for Portrait Mode, which follows this setting. While the LED theme is selected, its own colors are used regardless of this setting.", + "colorSchemeDescription": "Changes the colors of screens such as settings and line selection. \"Auto\" follows your device's dark mode setting. The screen shown while riding keeps the colors of the selected theme, except for Portrait Mode, which follows this setting. While the LED theme is selected, its own colors are used regardless of this setting, except for the Portrait Mode display.", "autoTheme": "Auto", "themeDescriptionAuto": "Theme changes automatically based on the current line.", "tokyoMetroLike": "Tokyo Metro", diff --git a/assets/translations/ja.json b/assets/translations/ja.json index 811dd2faf..f4c989b27 100644 --- a/assets/translations/ja.json +++ b/assets/translations/ja.json @@ -54,7 +54,7 @@ "colorSchemeAuto": "自動(端末の設定に合わせる)", "colorSchemeLight": "ライト", "colorSchemeDark": "ダーク", - "colorSchemeDescription": "設定や路線選択などの操作画面の配色を変更します。「自動」では端末のダークモード設定に合わせて自動的に切り替わります。走行中の画面はテーマ設定の配色のままですが、ポートレートモードの表示だけはこの設定に追従します。電光掲示板風テーマを選んでいる間は、この設定にかかわらず電光掲示板風テーマの配色が使われます。", + "colorSchemeDescription": "設定や路線選択などの操作画面の配色を変更します。「自動」では端末のダークモード設定に合わせて自動的に切り替わります。走行中の画面はテーマ設定の配色のままですが、ポートレートモードの表示だけはこの設定に追従します。電光掲示板風テーマを選んでいる間は、ポートレートモードの表示を除き、この設定にかかわらず電光掲示板風テーマの配色が使われます。", "autoTheme": "自動", "themeDescriptionAuto": "路線に応じて自動的にテーマが変わります。", "tokyoMetroLike": "東京メトロ風",