Skip to content

画面長押しで開く設定モーダルからテーマを選べるテーマ一覧モーダルを追加#5933

Merged
TinyKitten merged 3 commits into
devfrom
claude/add-theme-settings-modal-1wpl6
May 11, 2026
Merged

画面長押しで開く設定モーダルからテーマを選べるテーマ一覧モーダルを追加#5933
TinyKitten merged 3 commits into
devfrom
claude/add-theme-settings-modal-1wpl6

Conversation

@TinyKitten
Copy link
Copy Markdown
Member

@TinyKitten TinyKitten commented May 11, 2026

概要

長押しで開く設定モーダルから、テーマ(自動・路線各社風・LED 等)を直接選べるテーマ一覧モーダルを追加した。これまでテーマ変更には設定画面まで遷移する必要があったが、走行中の画面から離れずに切り替えできるようにする。

変更の種類

  • バグ修正
  • 新機能
  • リファクタリング
  • ドキュメント
  • CI/CD
  • その他

変更内容

  • SelectBoundSettingListModalthemeLabel / themeColor / onThemePress プロップを追加し、列車種別ボタンと同じ視覚で「テーマ」行(現在のテーマ名 + 色サンプル)を表示する。
  • ThemeListModal を新規追加。getSettingsThemes() を用いて全テーマを色グラデーション + 「使用中 / 選ぶ」状態パネル付きで列挙し、LED テーマ時もデザインが破綻しないよう分岐済み。
  • PermittedthemePreferenceAtom から現在のテーマ設定を取得し、列車種別モーダルと同じ「設定モーダルを閉じてアニメーション完了後に次モーダルを開く」フローでテーマ一覧モーダルを開く。選択時は AsyncStorage への保存 + atom 更新を行い、既存の ThemeSettings 画面と同じ永続化経路に揃える。
  • SelectBoundSettingListModal.test.tsx にテーマ行の表示/非表示・押下時のコールバック呼び出し・themeLabel 未指定時のフォールバック表示など 4 ケースを追加。

テスト

  • npm run lint が通ること
  • npm test が通ること
  • npm run typecheck が通ること

関連Issue

スクリーンショット(任意)


Generated by Claude Code

Summary by CodeRabbit

  • New Features

    • 設定画面にテーマ選択モーダルを追加。設定リストからテーマ一覧を開いて選べます。
    • 設定リストにテーマ行を表示し、現在のテーマ名と色が反映されます。選択は自動保存されUIに反映。
  • Bug Fixes / UX

    • 設定リストの閉鎖アニメーション後にテーマモーダルがスムーズに開くよう改善。
  • Tests

    • テーマ表示・切替・閉じる操作を検証するテストを追加。

Review Change Stack

@TinyKitten TinyKitten self-assigned this May 11, 2026
@github-actions github-actions Bot added the react label May 11, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 11, 2026

📝 Walkthrough

Walkthrough

新しい ThemeListModal を追加し、設定モーダルにテーマ行を追加、親コンポーネントで選択を AsyncStorage に永続化して状態を更新します。

Changes

Theme Selection Modal Integration

Layer / File(s) Summary
Theme Modal Type & Constants
src/components/ThemeListModal.tsx
ITEM_HEIGHT/HEADER_HEIGHT/FOOTER_HEIGHT 定数と Props 型を導入。
Theme Modal Styling & Layout
src/components/ThemeListModal.tsx
モーダル容器、ヘッダー、リスト行、スウォッチ、閉じるボタン用スタイルを追加(LED 対応)。
Theme Modal Core & Rendering
src/components/ThemeListModal.tsx
LED フラグ取得、テーマ項目派生、モーダル高さ計算、各アイテムのグラデーション/選択表示、keyExtractor を実装。
Theme Modal UI Build
src/components/ThemeListModal.tsx
CustomModal にヘッダー、FlatList、閉じるボタンを組み込み、onSelect/onClose を公開。
Settings Modal Theme Button
src/components/SelectBoundSettingListModal.tsx
PropsthemeLabel/themeColor/onThemePress を追加。テーマ色からテキスト・背景色をメモ化し、条件付きでテーマ行を表示。
Theme Button Test Coverage
src/components/SelectBoundSettingListModal.test.tsx
onThemePress の有無でボタン非表示/表示、themeLabel のフォールバック表示、押下時のハンドラ呼び出しを検証。
Parent Component Imports & Atom Setup
src/components/Permitted.tsx
React インポート更新、ThemeListModalTHEME_PREFERENCE 等のインポートを追加。
Parent Component State Management
src/components/Permitted.tsx
themePreferenceAtomuseAtom でバインドし、isThemeListModalVisiblependingThemeListModalRef を導入。
Parent Component Theme Handlers
src/components/Permitted.tsx
themeLabel/themeRowColor 計算、handleThemePress/handleSettingListClose/handleThemeListClose/handleThemeSelect を定義し、選択を AsyncStorage に永続化。
Parent Component UI Wiring
src/components/Permitted.tsx
SelectBoundSettingListModal にテーマラベル・色・ハンドラを渡し、ThemeListModal をレンダリングして可視性・選択ハンドラを接続。
ThemeListModal Tests
src/components/ThemeListModal.test.tsx
全テーマラベルのレンダリング、選択状態表示、onSelect の引数検証、onClose 呼び出し検証を追加。

🎯 3 (Moderate) | ⏱️ ~20 minutes

sequenceDiagram
  participant User
  participant SelectModal as SelectBoundSettingListModal
  participant Parent as PermittedLayout
  participant ThemeModal as ThemeListModal
  participant Storage as AsyncStorage
  participant Atom as themePreferenceAtom

  User->>SelectModal: tap "テーマ" ボタン
  SelectModal->>Parent: onThemePress()
  Parent->>SelectModal: close settings modal (start animation)
  Parent->>ThemeModal: open (after close animation)
  User->>ThemeModal: select theme (value)
  ThemeModal->>Parent: onSelect(theme)
  Parent->>Storage: setItem(THEME_PREFERENCE, theme)
  Storage-->>Parent: success / error
  Parent->>Atom: update themePreference
Loading

🐰 テーマ選びの窓を開き
モーダルを渡り歩き
選んだ色は記憶され
画面はその光に染まる
小さなボタンが世界を変える✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed このプルリクエストのタイトルは、設定モーダルからテーマを選べるテーマ一覧モーダルの追加という、変更の主要な目的を正確かつ簡潔に説明しています。
Description check ✅ Passed プルリクエストの説明は、リポジトリのテンプレート構造にほぼ準拠し、概要、変更の種類、変更内容、テスト、関連Issueのセクションが適切に記入されています。
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/add-theme-settings-modal-1wpl6

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/components/SelectBoundSettingListModal.test.tsx (1)

116-158: ⚡ Quick win

起点のボタンだけでなく、今回追加したモーダル遷移フローも1本は保護したいです。

ここで増えたのはテーマ行の表示確認までで、PR の主機能である onThemePress -> 設定モーダル close 完了 -> ThemeListModal 表示onSelect -> 永続化 が未テストです。PermittedThemeListModal の sibling test を1本追加しておくと、この変更の回帰耐性がかなり上がります。

As per coding guidelines, **/*.{test,spec}.{ts,tsx,js,jsx,py,java,go,cs}: Test agents in isolation and with integration tests to ensure correctness and compatibility.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/SelectBoundSettingListModal.test.tsx` around lines 116 - 158,
Add an integration test to cover the full theme-flow: render
SelectBoundSettingListModal (use defaultProps), provide an onThemePress handler
that triggers the modal transition, then simulate pressing the theme button
(call getByText('theme') and fireEvent.press) and assert that the parent modal
was closed (e.g., verify it's no longer in the tree or that a close callback was
invoked) and that ThemeListModal (or its Permitted sibling) is rendered; also
simulate selecting a theme in ThemeListModal and assert the onSelect persistence
callback was called with the chosen value. Locate the flow around the
SelectBoundSettingListModal component, the onThemePress prop,
ThemeListModal/Permitted rendering, and the onSelect handler to implement this
test.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/components/ThemeListModal.tsx`:
- Around line 185-191: The FlatList in ThemeListModal is allowed to grow by
content height and pushes the footer off-screen on small devices; constrain it
to the remaining modal space so it scrolls instead. Wrap the FlatList (or apply
directly to the FlatList) with a container/style that uses flex: 1 (e.g., set
style={{flex: 1}} on the FlatList or its parent View) so the list fills only the
available modal height and becomes scrollable; keep renderItem/keyExtractor the
same and preserve contentContainerStyle for item spacing.

---

Nitpick comments:
In `@src/components/SelectBoundSettingListModal.test.tsx`:
- Around line 116-158: Add an integration test to cover the full theme-flow:
render SelectBoundSettingListModal (use defaultProps), provide an onThemePress
handler that triggers the modal transition, then simulate pressing the theme
button (call getByText('theme') and fireEvent.press) and assert that the parent
modal was closed (e.g., verify it's no longer in the tree or that a close
callback was invoked) and that ThemeListModal (or its Permitted sibling) is
rendered; also simulate selecting a theme in ThemeListModal and assert the
onSelect persistence callback was called with the chosen value. Locate the flow
around the SelectBoundSettingListModal component, the onThemePress prop,
ThemeListModal/Permitted rendering, and the onSelect handler to implement this
test.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d9b78409-f780-47f9-91d2-1e11169b266b

📥 Commits

Reviewing files that changed from the base of the PR and between 997ca43 and 8496ebb.

📒 Files selected for processing (4)
  • src/components/Permitted.tsx
  • src/components/SelectBoundSettingListModal.test.tsx
  • src/components/SelectBoundSettingListModal.tsx
  • src/components/ThemeListModal.tsx

Comment thread src/components/ThemeListModal.tsx
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/components/ThemeListModal.test.tsx`:
- Around line 45-63: The tests for ThemeListModal are too loose: replace the
hardcoded label checks and the loose getAllByText('select').length > 1 assertion
with deterministic checks based on getSettingsThemes(); render <ThemeListModal
{...defaultProps} /> (and once with
currentPreference=THEME_PREFERENCE.TOKYO_METRO), then assert that every theme
key from getSettingsThemes() is present via getByText, assert
getAllByText('inUse') has length 1, and assert getAllByText('select') has length
equal to getSettingsThemes().length - 1 so the tests fail if themes are
added/removed or rendering changes.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 08f0406d-50b1-4b97-96b6-151870e7021a

📥 Commits

Reviewing files that changed from the base of the PR and between 8496ebb and 2f86710.

📒 Files selected for processing (2)
  • src/components/ThemeListModal.test.tsx
  • src/components/ThemeListModal.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/components/ThemeListModal.tsx

Comment thread src/components/ThemeListModal.test.tsx Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
src/components/ThemeListModal.test.tsx (1)

66-72: ⚡ Quick win

押下対象ラベルのハードコードを避けるとテスト耐性が上がります

Line 71 の 'tokyoMetroLike' 固定は、ラベルキー変更だけでテストが壊れます。THEME_PREFERENCE.TOKYO_METRO からラベルを引いて押下対象を決める方が安全です。

差分案
 it('テーマを押すと onSelect がそのテーマで呼ばれる', () => {
   const onSelect = jest.fn();
+  const metroTheme = getSettingsThemes().find(
+    (theme) => theme.preference === THEME_PREFERENCE.TOKYO_METRO,
+  );
+  if (!metroTheme) {
+    throw new Error('TOKYO_METRO theme not found');
+  }
   const { getByText } = render(
     <ThemeListModal {...defaultProps} onSelect={onSelect} />
   );
-  fireEvent.press(getByText('tokyoMetroLike'));
+  fireEvent.press(getByText(metroTheme.label));
   expect(onSelect).toHaveBeenCalledTimes(1);
   expect(onSelect).toHaveBeenCalledWith(THEME_PREFERENCE.TOKYO_METRO);
 });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/ThemeListModal.test.tsx` around lines 66 - 72, The test in
ThemeListModal.test.tsx hardcodes the label 'tokyoMetroLike' when pressing the
theme; instead derive the label from the source of truth to avoid brittleness.
Update the test to compute the target text from THEME_PREFERENCE.TOKYO_METRO (or
the same label resolver/mapping your app uses) and then call
fireEvent.press(getByText(...)) with that computed label, keeping the test's
usage of ThemeListModal and the onSelect jest.fn() intact.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/components/ThemeListModal.test.tsx`:
- Around line 66-72: The test in ThemeListModal.test.tsx hardcodes the label
'tokyoMetroLike' when pressing the theme; instead derive the label from the
source of truth to avoid brittleness. Update the test to compute the target text
from THEME_PREFERENCE.TOKYO_METRO (or the same label resolver/mapping your app
uses) and then call fireEvent.press(getByText(...)) with that computed label,
keeping the test's usage of ThemeListModal and the onSelect jest.fn() intact.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 44f2e3c5-cb29-4329-8bf5-0659ded600f9

📥 Commits

Reviewing files that changed from the base of the PR and between 2f86710 and e2b7bb3.

📒 Files selected for processing (2)
  • src/components/ThemeListModal.test.tsx
  • src/components/ThemeListModal.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/components/ThemeListModal.tsx

@TinyKitten TinyKitten merged commit e5fd23b into dev May 11, 2026
6 checks passed
@TinyKitten TinyKitten deleted the claude/add-theme-settings-modal-1wpl6 branch May 11, 2026 07:10
@TinyKitten TinyKitten mentioned this pull request May 11, 2026
9 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants