# 画面設計書 15-EditSave画面

## 概要

本ドキュメントは、Wikipedia iOSアプリにおける記事編集の保存確認画面（EditSaveViewController）の設計仕様を定義するものです。

### 本画面の処理概要

記事編集の保存確認画面は、ユーザーがWikipedia記事を編集した後、変更内容をWikipediaに公開（publish）する前の最終確認画面です。編集サマリーの入力、マイナー編集フラグの設定、ウォッチリストへの追加、ライセンス同意の確認を行います。

**業務上の目的・背景**：Wikipediaへの編集投稿は、コミュニティへの貢献として重要な機能です。しかし、編集には責任が伴うため、投稿前にサマリーの入力やマイナー編集の指定、ライセンスへの同意を明確にする必要があります。本画面は、これらの確認事項を一箇所にまとめ、編集の品質と透明性を確保します。また、一時アカウント（Temp Account）機能への対応も含まれています。

**画面へのアクセス方法**：記事編集画面（EditorViewController）から編集完了時に遷移します。

**主要な操作・処理内容**：
1. 編集サマリーの入力（定型文ボタンまたは自由入力）
2. マイナー編集フラグの設定（トグルスイッチ）
3. ウォッチリストへの追加設定（トグルスイッチ、ログインユーザーのみ）
4. Webプレビューの表示（オプション）
5. 「Publish」ボタンで編集を公開
6. CAPTCHA認証（必要な場合）
7. Abuse Filter警告/ブロック対応

**画面遷移**：
- 遷移元: EditorViewController（記事編集画面）
- 遷移先: なし（編集完了後は呼び出し元に戻る）、CAPTCHA画面（埋め込み）

**権限による表示制御**：
- 非ログインユーザー: ウォッチリストオプション非表示、ログイン誘導メッセージ表示
- 一時アカウント: 一時アカウント通知バナー表示
- ログインユーザー: すべての機能が利用可能

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 23 | 編集保存 | 主機能 | 編集内容のWikipediaへの投稿 |
| 26 | 要約編集 | 補助機能 | 編集時のサマリー入力 |

## 画面種別

確認 / 入力

## URL/ルーティング

iOSネイティブアプリのため、URLルーティングは適用されません。NavigationControllerのプッシュ遷移で表示します。

## 入出力項目

| 項目名 | 型 | 入力/出力 | 必須 | 説明 |
|--------|-----|---------|------|------|
| sectionID | Int | 入力 | 任意 | 編集対象のセクションID（全体編集時はnil） |
| pageURL | URL | 入力 | 必須 | 編集対象の記事URL |
| languageCode | String | 入力 | 任意 | 言語コード |
| dataStore | MWKDataStore | 入力 | 必須 | データストア |
| source | EditorViewController.Source | 入力 | 任意 | 編集元の種別 |
| wikitext | String | 入力 | 必須 | 編集後のウィキテキスト |
| theme | Theme | 入力 | 必須 | 表示テーマ |
| needsWebPreviewButton | Bool | 入力 | 任意 | Webプレビューボタン表示フラグ |
| needsSuppressPosting | Bool | 入力 | 任意 | 投稿を抑制するフラグ（テスト用） |
| editTags | [WMFEditTag] | 入力 | 任意 | 編集タグ |
| cannedSummaryTypes | [EditSummaryViewCannedButtonType] | 入力 | 任意 | 定型サマリーの種類 |
| savedData | SaveData | 入力 | 任意 | 前回入力データの復元 |
| delegate | EditSaveViewControllerDelegate | 入力 | 必須 | デリゲート |

## 表示項目

| 項目名 | 表示形式 | 説明 |
|--------|---------|------|
| 編集サマリー入力 | テキストフィールド | EditSummaryViewControllerを埋め込み |
| 定型サマリーボタン | ボタン群 | typo, grammar, linkなどの定型文 |
| マイナー編集ラベル | テキスト | "This is a minor edit" |
| マイナー編集トグル | UISwitch | マイナー編集フラグ |
| マイナー編集説明ボタン | ボタン | "Learn more about minor edits" |
| ウォッチリストラベル | テキスト | "Watch this page" |
| ウォッチリストトグル | UISwitch | ウォッチリスト追加フラグ |
| ウォッチリスト説明ボタン | ボタン | "Learn more about your Watchlist" |
| ライセンス説明文 | テキストビュー | CC BY-SA 4.0、GFDLへのリンク付き説明 |
| ログイン誘導文 | テキストビュー | 非ログイン時のログインリンク |
| Webプレビューボタン | ボタン | "Show web preview" |
| CAPTCHA入力 | 埋め込みVC | WMFCaptchaViewController |
| 一時アカウント通知 | バナー | 一時アカウントユーザーへの説明 |

## イベント仕様

### 1-Publishボタンタップ

編集内容をWikipediaに公開する処理。

- "Publishing..."アラートを表示
- WikiTextSectionUploader.uploadWikiText()を呼び出し
- 成功時: delegate.editSaveViewControllerDidSave()を呼び出し
- 失敗時: エラー種別に応じた処理

### 2-CAPTCHA認証

サーバーからCAPTCHA要求があった場合の処理。

- WMFCaptchaViewControllerにCAPTCHA情報を設定
- ユーザーが解答を入力後、再度save()を実行
- captchaSolutionChanged()でボタン状態を更新

### 3-Abuse Filter対応

編集内容がAbuse Filterに引っかかった場合の処理。

- **警告（Warning）**: wmf_showAbuseFilterWarningPanel()を表示、「Publish anyway」で続行可能
- **禁止（Disallow）**: wmf_showAbuseFilterDisallowPanel()を表示、編集不可
- abuseFilterCodeを記録

### 4-ブロック対応

ユーザーがブロックされている場合の処理。

- wmf_showBlockedPanel()を表示
- ブロック理由のHTMLを表示
- リンクタップ時にログ記録

### 5-マイナー編集ボタンタップ

マイナー編集の説明ページを表示。

- navigate(to: URL)でMediaWikiのヘルプページを開く
- imageRecLoggingDelegateでログ記録

### 6-ウォッチリストボタンタップ

ウォッチリストの説明ページを表示。

- navigate(to: URL)でMediaWikiのヘルプページを開く
- imageRecLoggingDelegateでログ記録

### 7-ログインリンクタップ

ログイン画面を表示。

- WMFLoginViewControllerをモーダル表示

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| 編集公開（成功） | - | API呼び出し | WikiMedia APIに投稿 |

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

ローカルデータベースへの直接的な更新はありません。編集内容はWikiMedia APIを通じてサーバーに送信されます。

## メッセージ仕様

| メッセージID | 種別 | メッセージ内容 | 表示条件 |
|-------------|------|--------------|---------|
| wikitext-preview-save-changes-title | タイトル | "Save changes" | ナビゲーションバー |
| wikitext-upload-save | アラート | "Publishing..." | 公開処理中 |
| wikitext-upload-save-terms-and-licenses-ccsa4 | 説明文 | ライセンス同意文 | 常時表示 |
| wikitext-upload-save-anonymously-or-login | 説明文 | ログイン誘導文 | 非ログイン時 |
| edit-minor-text | ラベル | "This is a minor edit" | 常時表示 |
| edit-minor-learn-more-text | ボタン | "Learn more about minor edits" | 常時表示 |
| edit-watch-this-page-text | ラベル | "Watch this page" | ログイン時 |
| edit-watch-list-learn-more-text | ボタン | "Learn more about your Watchlist" | ログイン時 |
| edit-show-web-preview | ボタン | "Show web preview" | needsWebPreviewButton時 |
| saveViewTempAccountNotice | バナー | 一時アカウント通知 | 一時アカウント時 |
| saveViewTempAccountWarning | バナー | 一時アカウント警告 | 非ログイン時（一時アカウント有効Wiki） |

## 例外処理

| 例外状況 | 処理内容 |
|---------|---------|
| CAPTCHA要求 | WMFCaptchaViewControllerを表示、解答入力後に再送信 |
| Abuse Filter警告 | 警告パネルを表示、「Publish anyway」で続行可能 |
| Abuse Filter禁止 | 禁止パネルを表示、編集不可 |
| ブロック | ブロックパネルを表示、ブロック理由を表示 |
| 保護ページ | エラーアラートを表示 |
| サーバーエラー | エラーアラートを表示 |
| ネットワークエラー | エラーアラートを表示 |

## 備考

- WMFScrollViewControllerを継承（キーボード対応）
- EditSummaryViewControllerを子ViewControllerとして埋め込み
- WMFCaptchaViewControllerを子ViewControllerとして埋め込み
- EditSaveViewControllerDelegateで編集結果を通知
- EditSaveViewControllerEditorLoggingDelegateでエディタログを記録
- EditSaveViewControllerImageRecLoggingDelegateで画像推薦ログを記録
- EditingFlowViewControllerプロトコルに準拠

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | EditSaveViewController.swift | `Wikipedia/Code/EditSaveViewController.swift` | EditorChanges構造体（6-8行目）、SaveData構造体（51-55行目） |
| 1-2 | WikiTextSectionUploaderErrorType | （参照のみ） | エラー種別の定義 |

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | EditSaveViewController.swift | `Wikipedia/Code/EditSaveViewController.swift` | viewDidLoad()（187-234行目）、save()（435-497行目） |

**主要処理フロー**:
1. **187-234行目**: viewDidLoad - UI設定、子VC追加、ウォッチリスト状態取得
2. **302-305行目**: configureNavigationBar - ナビゲーションバー設定
3. **435-497行目**: save - 編集公開処理
4. **500-549行目**: handleEditSuccess - 成功時処理
5. **551-659行目**: handleEditFailure - 失敗時処理

#### Step 3: 子ViewControllerを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | EditSummaryViewController.swift | `Wikipedia/Code/EditSummaryViewController.swift` | サマリー入力UI |
| 3-2 | WMFCaptchaViewController.swift | `Wikipedia/Code/WMFCaptchaViewController.swift` | CAPTCHA認証UI |

#### Step 4: エラーハンドリングを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | EditSaveViewController.swift | `Wikipedia/Code/EditSaveViewController.swift` | handleEditFailure()（551-659行目） |

**主要処理フロー**:
- **558-572行目**: CAPTCHA処理
- **573-602行目**: Abuse Filter処理
- **607-631行目**: ブロック処理

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

```
EditSaveViewController
    │
    ├─ viewDidLoad()
    │      ├─ setupButtonsAndTitle()
    │      ├─ updateTextViews()
    │      ├─ wmf_add(childController: captchaViewController)
    │      ├─ wmf_add(childController: editSummaryViewController)
    │      └─ fetchWatchlistStatusAndUpdateToggle()
    │
    ├─ goForward() [Publish button]
    │      └─ save()
    │             └─ wikiTextSectionUploader.uploadWikiText()
    │                    ├─ [success] handleEditSuccess()
    │                    │              └─ delegate?.editSaveViewControllerDidSave()
    │                    └─ [failure] handleEditFailure()
    │                                   ├─ [needsCaptcha] captchaViewController表示
    │                                   ├─ [abuseFilter] wmf_showAbuseFilterPanel()
    │                                   ├─ [blocked] wmf_showBlockedPanel()
    │                                   └─ [other] WMFAlertManager.showErrorAlert()
    │
    └─ WMFCaptchaViewControllerDelegate
           └─ captchaSolutionChanged() → highlightCaptchaSubmitButton()
```

### データフロー図

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

wikitext                  WikiTextSectionUploader             WikiMedia API
pageURL              ───▶ uploadWikiText()                ───▶ (記事更新)
sectionID                      │
summaryText                    │
                               ▼
                         handleEditSuccess()
                               │
                               ▼
                         delegate?.editSaveViewControllerDidSave()
                               │
                               ▼
                         EditorChanges(newRevisionID)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| EditSaveViewController.swift | `Wikipedia/Code/EditSaveViewController.swift` | ソース | メインViewController |
| EditSaveViewController.xib | `Wikipedia/Code/EditSaveViewController.xib` | XIB | レイアウト定義 |
| EditSummaryViewController.swift | `Wikipedia/Code/EditSummaryViewController.swift` | ソース | サマリー入力子VC |
| WMFCaptchaViewController.swift | `Wikipedia/Code/WMFCaptchaViewController.swift` | ソース | CAPTCHA子VC |
| WikiTextSectionUploader.swift | `Wikipedia/Code/WikiTextSectionUploader.swift` | ソース | API呼び出し |
| EditAttemptFunnel.swift | `Wikipedia/Code/EditAttemptFunnel.swift` | ソース | 編集イベントログ |
| WMFArticleDataController.swift | `WMFData/Sources/WMFArticleDataController.swift` | ソース | ウォッチリスト状態取得 |
