# 画面設計書 87-EditSummary画面

## 概要

本ドキュメントは、Wikipedia iOSアプリにおけるEditSummary画面の設計仕様を定義するものである。この画面は、記事編集時に編集サマリー（要約）を入力するためのコンポーネントである。

### 本画面の処理概要

EditSummary画面は、Wikipedia記事の編集完了時に編集内容の要約を入力するためのインターフェースを提供する。テキストフィールドによる自由入力に加え、よく使用される編集理由（タイポ修正、文法修正、リンク追加など）をワンタップで入力できるプリセットボタン（Canned Summary）を備えている。

**業務上の目的・背景**：Wikipediaでは、編集の透明性と履歴の追跡可能性を担保するため、編集時にサマリー（要約）を入力することが推奨されている。サマリーは編集履歴に表示され、他の編集者がなぜその変更が行われたかを理解するのに役立つ。本画面は、モバイルデバイスでのサマリー入力を簡便にし、よくある編集理由をプリセットで提供することで、ユーザーの入力負担を軽減する。

**画面へのアクセス方法**：EditSave画面の子コンポーネントとして埋め込まれ、編集保存フローの一部として表示される。単独でナビゲーション遷移することはない。

**主要な操作・処理内容**：
1. テキストフィールドでの自由入力によるサマリー記入
2. プリセットボタン（Fixed typo、Fixed grammar、Added links）のタップで定型文を自動入力
3. 「Learn more」ボタンで編集サマリーに関する詳細情報を表示
4. 入力文字数の制限（255文字まで）
5. RTL言語対応のレイアウト調整

**画面遷移**：
- 遷移元：EditSave画面（親コンテナ）
- 遷移先：なし（Learn moreはdelegate経由で処理）

**権限による表示制御**：特になし。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 26 | 要約編集 | 主機能 | 編集サマリー入力 |
| 21 | 記事編集 | 関連機能 | 編集フローの一部 |

## 画面種別

入力フォーム（埋め込みコンポーネント）

## URL/ルーティング

iOSネイティブアプリのため、URLルーティングなし。Storyboard/XIBからインスタンス化され、EditSave画面のコンテナに埋め込まれる。

## 入出力項目

| 項目名 | 型 | 入力/出力 | 必須 | 説明 |
|--------|------|---------|------|------|
| languageCode | String | 入力 | 必須 | ローカライズ用言語コード（デフォルト: "en"） |
| cannedSummaryTypes | [EditSummaryViewCannedButtonType] | 入力 | 必須 | プリセットボタンの種類 |
| theme | Theme | 入力 | 必須 | 現在のテーマ設定 |
| summary (via delegate) | String | 出力 | - | 入力されたサマリーテキスト |

## 表示項目

| 項目名 | 説明 | 表示形式 |
|--------|------|----------|
| サマリーラベル | 「Add an edit summary」 | テキスト |
| Learn moreボタン | 詳細情報へのリンク | ボタン |
| サマリーテキストフィールド | 「How did you improve the article?」（プレースホルダー） | テキスト入力 |
| Fixed typoボタン | タイポ修正のプリセット | ボタン |
| Fixed grammarボタン | 文法修正のプリセット | ボタン |
| Added linksボタン | リンク追加のプリセット | ボタン |

## イベント仕様

### 1-テキストフィールド編集

テキストフィールドの内容が変更された際の処理。

1. `textFieldDidChange(textField:)`が呼び出される
2. `notifyDelegateOfSummaryChange()`を実行
3. delegateの`summaryChanged(newSummary:)`を呼び出し

### 2-プリセットボタンタップ

Canned Summaryボタンをタップした際の処理。

1. `cannedSummaryButtonTapped(sender:)`が呼び出される
2. ボタンのtitleLabel?.textを取得
3. `updateInputText(to:)`でテキストフィールドを更新
4. `notifyDelegateOfSummaryChange()`でdelegate通知

### 3-Learn moreボタンタップ

Learn moreボタンをタップした際の処理。

1. `learnMoreButtonTapped(sender:)`が呼び出される
2. delegateの`learnMoreButtonTapped(sender:)`を呼び出し
3. 親画面（EditSave）でヘルプ画面への遷移処理

### 4-文字数制限チェック

テキストフィールド入力時の文字数制限処理。

1. `textField(_:shouldChangeCharactersIn:replacementString:)`が呼び出される
2. 新しい文字列長を計算（現在の長さ + 追加文字数 - 置換範囲長）
3. maximumSummaryLength（255）以下ならtrue、超過ならfalseを返す

### 5-RTL言語対応設定

言語コードに基づくセマンティックコンテンツ属性の設定。

1. `setupSemanticContentAttibute()`が呼び出される
2. `MWKLanguageLinkController.semanticContentAttribute`で言語方向を取得
3. addSummaryLabel、learnMoreButton、summaryTextFieldに設定
4. テキストアライメントを右（RTL）または左（LTR）に設定

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

本画面では直接的なデータベース操作は行わない。入力されたサマリーテキストはdelegateを通じて親画面に渡され、編集保存処理で使用される。

## メッセージ仕様

| メッセージID | 種別 | メッセージ内容 | 表示条件 |
|-------------|------|--------------|----------|
| edit-summary-add-summary-text | ラベル | Add an edit summary | サマリーラベル |
| edit-summary-placeholder-text | プレースホルダー | How did you improve the article? | テキストフィールド |
| edit-summary-choice-fixed-typos | ボタン | Fixed typo | プリセットボタン |
| edit-summary-choice-fixed-grammar | ボタン | Fixed grammar | プリセットボタン |
| edit-summary-choice-linked-words | ボタン | Added links | プリセットボタン |
| edit-summary-choice-added-image | ボタン | Added image | プリセットボタン（画像追加時） |
| edit-summary-choice-added-image-and-caption | ボタン | Added image and caption | プリセットボタン（画像+キャプション追加時） |

## 例外処理

| 例外条件 | 処理内容 |
|---------|---------|
| 255文字超過 | 入力を拒否（shouldChangeCharactersIn = false） |
| ボタンタイトル取得失敗 | assertionFailureでデバッグ時警告 |
| cannedSummaryTypesがボタン数を超過 | assertionFailure、超過分は無視 |

## 備考

- EditSummaryViewCannedButtonType enumでプリセットボタンの種類を定義
- 各ボタンタイトルはlanguageCodeに基づいてローカライズ
- SummaryButtonScrollViewはボタンの最大高さに基づいてintrinsicContentSizeを計算
- maximumSummaryLengthは255文字（Wikipedia APIの制限に準拠）
- Themeableプロトコルに準拠し、テーマ変更に対応

---

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

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

### 推奨読解順序

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

プリセットボタンの種類定義を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | EditSummaryViewController.swift | `Wikipedia/Code/EditSummaryViewController.swift` | EditSummaryViewCannedButtonType enum |

**読解のコツ**: enumのcaseごとにbuttonTitle(for:)でローカライズ文字列を返す。

**主要処理フロー**:
- **9-26行目**: `EditSummaryViewCannedButtonType` - typo、grammar、link、addedImage、addedImageAndCaption

#### Step 2: ViewControllerを理解する

基本構造とプロパティを把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | EditSummaryViewController.swift | `Wikipedia/Code/EditSummaryViewController.swift` | プロパティ、IBOutlet、delegate |

**主要処理フロー**:
1. **28-29行目**: `maximumSummaryLength` = 255
2. **31-35行目**: プロパティ定義（theme、languageCode、cannedSummaryTypes、delegate）
3. **38-45行目**: IBOutlet定義

#### Step 3: ライフサイクルとセットアップを理解する

viewDidLoadでの初期化処理を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | EditSummaryViewController.swift | `Wikipedia/Code/EditSummaryViewController.swift` | viewDidLoad、setupSemanticContentAttibute |

**主要処理フロー**:
- **49-68行目**: `viewDidLoad()` - ラベル/ボタン設定、RTL対応、テーマ適用
- **70-78行目**: `setupSemanticContentAttibute()` - 言語方向設定

#### Step 4: イベントハンドリングを理解する

ユーザー操作に対する処理を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | EditSummaryViewController.swift | `Wikipedia/Code/EditSummaryViewController.swift` | IBAction、UITextFieldDelegate |

**主要処理フロー**:
- **80-82行目**: `learnMoreButtonTapped` - delegate通知
- **84-86行目**: `textFieldDidChange` - サマリー変更通知
- **92-98行目**: `cannedSummaryButtonTapped` - プリセット適用
- **149-157行目**: `UITextFieldDelegate` - 文字数制限

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

```
EditSummaryViewController
    │
    ├─ viewDidLoad()
    │      ├─ cannedEditSummaryButtons設定（numberOfLines等）
    │      ├─ ラベル/ボタンテキスト設定
    │      ├─ summaryTextField設定（placeholder、delegate、target）
    │      ├─ updateCannedSummaryButtons()
    │      ├─ setupSemanticContentAttibute()
    │      └─ apply(theme:)
    │
    ├─ textFieldDidChange(textField:)
    │      └─ notifyDelegateOfSummaryChange()
    │             └─ delegate?.summaryChanged(newSummary:)
    │
    ├─ cannedSummaryButtonTapped(sender:)
    │      ├─ updateInputText(to:)
    │      │      └─ summaryTextField.text設定
    │      └─ notifyDelegateOfSummaryChange()
    │
    ├─ learnMoreButtonTapped(sender:)
    │      └─ delegate?.learnMoreButtonTapped(sender:)
    │
    └─ UITextFieldDelegate
           ├─ textFieldShouldReturn(_:) → true
           └─ textField(_:shouldChangeCharactersIn:) → 文字数チェック
```

### データフロー図

```
[ユーザー入力]            [ViewController]           [delegate]

テキスト入力 ─────────▶ textFieldDidChange ─────▶ summaryChanged()
                              │
プリセットタップ ─────▶ cannedSummaryButtonTapped
                              │
                              ▼
                    updateInputText() → テキスト更新
                              │
                              ▼
                    notifyDelegateOfSummaryChange()
                              │
                              └──────────────────▶ summaryChanged()

Learn moreタップ ────▶ learnMoreButtonTapped ──▶ learnMoreButtonTapped()
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| EditSummaryViewController.swift | `Wikipedia/Code/EditSummaryViewController.swift` | ソース | メインViewController |
| EditSummaryViewController.xib | `Wikipedia/Code/` | XIB | UIレイアウト（推定） |
| EditSaveViewController.swift | `Wikipedia/Code/EditSaveViewController.swift` | ソース | 親画面 |
| ThemeableTextField.swift | `Wikipedia/Code/ThemeableTextField.swift` | ソース | テーマ対応テキストフィールド |
| MWKLanguageLinkController | `WMF/Sources/WMF/` | ソース | 言語方向判定 |
