# 画面設計書 75-ReadingThemesControls画面

## 概要

本ドキュメントは、Wikipedia iOSアプリの読書テーマコントロール画面（ReadingThemesControlsViewController）の設計を記述したものである。

### 本画面の処理概要

ReadingThemesControls画面は、記事閲覧時の表示設定をリアルタイムで調整するためのポップオーバー画面である。画面の明るさ、テキストサイズ、カラーテーマ（ライト、セピア、ダーク、ブラック）をユーザーが簡単に変更できるインターフェースを提供する。設定変更は即座にアプリ全体に反映される。

**業務上の目的・背景**：読書体験の最適化は、長時間のコンテンツ閲覧において非常に重要である。ユーザーの視力、周囲の明るさ、個人的な好みに応じて表示をカスタマイズできることで、快適な読書体験を実現する。特にダーク/ブラックモードは夜間の閲覧やバッテリー節約に有効であり、セピアモードは目の疲れを軽減する効果がある。本画面は記事閲覧中に素早くアクセスできるポップオーバーとして設計されている。

**画面へのアクセス方法**：Article画面のツールバーにある「Aa」ボタン（テキスト設定ボタン）をタップすることでポップオーバーとして表示される。iPad等では指定された位置からポップオーバーとして、iPhoneではシートとして表示される。

**主要な操作・処理内容**：
1. 画面明るさスライダーで端末の画面輝度を調整
2. テキストサイズスライダーでフォントサイズを段階的に調整
3. テーマボタン（ライト、セピア、ダーク、ブラック）でカラーテーマを切り替え
4. シンタックスハイライトスイッチでコード表示の色分けを切り替え（エディタ使用時のみ表示）
5. 設定変更は即座にNotificationCenterを通じてアプリ全体に通知される

**画面遷移**：
- 遷移元：Article画面（テキスト設定ボタンタップ）、編集画面等
- 遷移先：なし（設定変更後は自動的に閉じるか、画面外タップで閉じる）

**権限による表示制御**：特になし。全ユーザーが同一の操作・表示を利用可能。ただし、シンタックスハイライトセクションはshowsSyntaxHighlightingプロパティにより表示/非表示が制御される。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 62 | テーマ適用 | 主機能 | 読書テーマコントロール |
| 47 | 外観設定 | 補助機能 | テーマ・フォントサイズの調整 |

## 画面種別

ポップオーバー / シート

## URL/ルーティング

ネイティブ画面のため、URLベースのルーティングは存在しない。ArticleViewControllerからポップオーバー表示される。

## 入出力項目

| 項目名 | 型 | 入力/出力 | 説明 |
|--------|-----|----------|------|
| theme | Theme | 入力 | 適用するテーマ |
| showsSyntaxHighlighting | Bool | 入力 | シンタックスハイライトセクションの表示有無 |
| needsExtraTopSpacing | Bool | 入力 | 上部余白の追加有無 |
| maximumValue | Int | 入力 | テキストサイズスライダーの最大値 |
| currentValue | Int | 入力 | テキストサイズスライダーの現在値 |

## 表示項目

| 項目名 | データソース | 説明 |
|--------|-------------|------|
| 明るさスライダー | UIScreen.main.brightness | 画面明るさ（0.0〜1.0） |
| テキストサイズスライダー | SWStepSlider | 段階的なテキストサイズ選択 |
| ライトテーマボタン | Theme.light | 白背景テーマ |
| セピアテーマボタン | Theme.sepia | セピア色背景テーマ |
| ダークテーマボタン | Theme.dark | 暗い背景テーマ |
| ブラックテーマボタン | Theme.black | 黒背景テーマ（OLED向け） |
| シンタックスハイライトスイッチ | UserDefaults.wmf_IsSyntaxHighlightingEnabled | コードの色分け有効化 |
| 明るさアイコン（小/大） | UIImageView | 明るさの視覚的インジケーター |
| テキストサイズアイコン（T小/T大） | UIImageView | テキストサイズの視覚的インジケーター |

## イベント仕様

### 1-明るさスライダー変更

brightnessSliderValueChanged(_:)が呼ばれ、UIScreen.main.brightnessに値を設定。logBrightnessChange()でイベントログ記録（0.3秒のデバウンス付き）。

### 2-テキストサイズスライダー変更

fontSliderValueChanged(_:)が呼ばれ、delegateのfontSizeSliderValueChangedInController()に通知。

### 3-テーマボタン押下

各テーマボタン（lightThemeButtonPressed、sepiaThemeButtonPressed、darkThemeButtonPressed、blackThemeButtonPressed）が押されると、userDidSelect(theme:)を呼び出し、NotificationCenter経由でWMFUserDidSelectThemeNotificationを投稿。

### 4-シンタックスハイライトスイッチ変更

syntaxHighlightingSwitched(_:)が呼ばれ、delegateのtoggleSyntaxHighlighting()を呼び出し、UserDefaults.wmf_IsSyntaxHighlightingEnabledを更新。

### 5-画面明るさ変更通知

UIScreen.brightnessDidChangeNotificationを監視し、外部からの明るさ変更時にスライダー値を更新。

## データベース更新仕様

### 操作別データベース影響一覧

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| テーマ選択 | UserDefaults | UPDATE | テーマ名を保存 |
| シンタックスハイライト切替 | UserDefaults | UPDATE | wmf_IsSyntaxHighlightingEnabledを保存 |

### テーブル別更新項目詳細

#### UserDefaults

| 操作 | 項目（キー名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | theme | 選択したテーマ名 | NotificationCenter経由で通知 |
| UPDATE | wmf_IsSyntaxHighlightingEnabled | true/false | スイッチの状態 |

## メッセージ仕様

| メッセージID | 種別 | 表示条件 | メッセージ内容 |
|-------------|------|---------|---------------|
| reading-themes-controls-accessibility-brightness-slider | アクセシビリティ | 常時 | "Brightness slider" |
| reading-themes-controls-accessibility-light-theme-button | アクセシビリティ | 常時 | "Light theme" |
| reading-themes-controls-accessibility-sepia-theme-button | アクセシビリティ | 常時 | "Sepia theme" |
| reading-themes-controls-accessibility-dark-theme-button | アクセシビリティ | 常時 | "Dark theme" |
| reading-themes-controls-accessibility-black-theme-button | アクセシビリティ | 常時 | "Black theme" |
| reading-themes-controls-syntax-highlighting | ラベル | showsSyntaxHighlighting時 | "Syntax Highlighting" |

## 例外処理

| 例外ケース | 処理内容 |
|-----------|---------|
| visibleがfalse時 | fontSliderValueChangedはdelegateに通知しない |
| traitCollection.displayScaleが0以下 | ボタンのボーダー幅を0.5に設定 |

## 備考

- UIViewControllerを継承し、Themeableプロトコルを実装
- nibName: "ReadingThemesControlsViewController"でxibからUIを読み込み
- preferredContentSizeはstackViewのサイズから自動計算
- テーマボタンは選択状態でボーダー幅2px、非選択で1px/displayScale
- ダーク/ブラックテーマ選択時はwmf_isImageDimmingEnabledの状態も反映
- WMFUserDidSelectThemeNotificationの通知でアプリ全体にテーマ変更を伝播
- SWStepSliderは段階的なスライダーコントロール（サードパーティライブラリ）

---

## コードリーディングガイド

本画面を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

まず、テーマ関連のデータ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Theme.swift | `Wikipedia/Code/` | テーマ定義とカラー設定 |
| 1-2 | UserDefaults+Extensions | `Wikipedia/Code/` | テーマ設定の永続化 |

**読解のコツ**: Theme構造体は.light, .sepia, .dark, .black等の静的プロパティを持ち、それぞれの配色を定義している。

#### Step 2: エントリーポイントを理解する

処理の起点となるファイル・関数を特定する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | ReadingThemesControlsViewController.swift | `Wikipedia/Code/ReadingThemesControlsViewController.swift` | 本画面のメインViewController |

**主要処理フロー**:
1. **行64-106**: viewDidLoadで初期設定、アクセシビリティラベル設定、テーマボタン色設定
2. **行159-164**: viewWillAppearでvisibleフラグ設定とテーマ適用
3. **行200-234**: 各ボタン・スライダーのIBAction実装

#### Step 3: テーマ切り替えを理解する

テーマ選択時の処理フローを把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | ReadingThemesControlsViewController.swift | `Wikipedia/Code/ReadingThemesControlsViewController.swift` | テーマ選択処理 |

**主要処理フロー**:
- **行211-213**: userDidSelect(theme:)でNotificationCenterに通知
- **行12-14**: 通知名とuserInfoキーの定義

#### Step 4: UI更新を理解する

apply(theme:)によるUI更新処理を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | ReadingThemesControlsViewController.swift | `Wikipedia/Code/ReadingThemesControlsViewController.swift` | Themeable実装 |

**主要処理フロー**:
- **行240-281**: apply(theme:)で全UI要素の色を更新
- **行113-125**: applyBorder(to:)とremoveBorderFrom(_:)でボタンの選択状態を視覚化

### プログラム呼び出し階層図

```
ReadingThemesControlsViewController
    │
    ├─ viewDidLoad() [行64-106]
    │      ├─ setValues() [行149-153]（view読み込み後に呼び出し）
    │      ├─ brightnessSlider.value = UIScreen.main.brightness
    │      ├─ アクセシビリティラベル設定
    │      └─ テーマボタン背景色設定
    │
    ├─ viewWillAppear(_:) [行159-164]
    │      └─ apply(theme:) [行240-281]
    │             ├─ removeBorderFrom() 全ボタン
    │             └─ applyBorder(to:) 選択テーマボタン
    │
    ├─ brightnessSliderValueChanged(_:) [行200-203]
    │      └─ UIScreen.main.brightness = value
    │
    ├─ fontSliderValueChanged(_:) [行205-209]
    │      └─ delegate?.fontSizeSliderValueChangedInController()
    │
    └─ lightThemeButtonPressed(_:) 等 [行216-230]
           └─ userDidSelect(theme:) [行211-213]
                  └─ NotificationCenter.default.post(
                         name: WMFUserDidSelectThemeNotification)
```

### データフロー図

```
[入力]                    [処理]                           [出力]

ユーザー操作 ─────────▶ IBAction
                              │
    ┌─────────────────────────┼─────────────────────────┐
    │                         │                         │
    ▼                         ▼                         ▼
明るさスライダー         テキストサイズ            テーマボタン
    │                    スライダー                    │
    ▼                         │                         ▼
UIScreen.main             delegate?.             NotificationCenter
.brightness            fontSizeSlider           .post(WMFUserDid
                      ValueChanged()            SelectTheme...)
    │                         │                         │
    ▼                         ▼                         ▼
端末画面輝度変更      呼び出し元で処理        アプリ全体のテーマ変更
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| ReadingThemesControlsViewController.swift | `Wikipedia/Code/ReadingThemesControlsViewController.swift` | ソース | 本画面のメインViewController |
| ReadingThemesControlsViewController.xib | `Wikipedia/Code/` | XIB | 本画面のUIレイアウト |
| Theme.swift | `Wikipedia/Code/Theme.swift` | ソース | テーマ定義 |
| SWStepSlider.swift | `Wikipedia/Third Party Code/SWStepSlider/SWStepSlider.swift` | ソース | 段階的スライダーコントロール |
| WMFReadingThemesControlsViewControllerDelegate | `Wikipedia/Code/ReadingThemesControlsViewController.swift` | プロトコル | デリゲートプロトコル（行3-7で定義） |
| Themeable.swift | `Wikipedia/Code/Themeable.swift` | プロトコル | テーマ適用プロトコル |
| UserDefaults+Extensions | `Wikipedia/Code/` | 拡張 | UserDefaults拡張（テーマ保存） |
