# 画面設計書 20-EditNotices画面

## 概要

本ドキュメントは、Wikipedia iOSアプリにおける編集通知画面（EditNoticesViewController）の設計仕様を定義するものです。

### 本画面の処理概要

編集通知画面は、Wikipedia記事を編集する前にユーザーに表示される重要な通知・警告を表示するモーダル画面です。特定の記事やトピックに関する編集ガイドライン、警告、注意事項などがWikipediaサーバーから取得され、HTML形式で表示されます。

**業務上の目的・背景**：Wikipediaの記事編集には、特定のルールやガイドラインが適用される場合があります。例えば、論争的なトピック、存命人物の記事、頻繁に荒らされる記事などには、編集前に確認すべき通知があります。本画面は、これらの通知をユーザーに確実に伝え、ガイドラインに沿った編集を促します。

**画面へのアクセス方法**：記事編集を開始する際、該当記事に編集通知が設定されている場合に自動的にモーダル表示されます。「常に表示」設定がONの場合は毎回表示されます。

**主要な操作・処理内容**：
1. 編集通知のHTML内容を表示
2. 「Done」ボタンで閉じる
3. 「常に編集通知を表示」トグルの設定
4. 通知内のリンクをタップして関連ページに遷移

**画面遷移**：
- 遷移元: EditorViewController（記事編集画面）
- 遷移先: リンク先ページ（Safari/WebView）、閉じて編集画面に戻る

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

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 21 | ウィキテキスト編集 | 主機能 | 編集開始時の通知表示 |

## 画面種別

通知 / 確認

## URL/ルーティング

iOSネイティブアプリのため、URLルーティングは適用されません。モーダル表示されます。

## 入出力項目

| 項目名 | 型 | 入力/出力 | 必須 | 説明 |
|--------|-----|---------|------|------|
| theme | Theme | 入力 | 必須 | 表示テーマ |
| viewModel | EditNoticesViewModel | 入力 | 必須 | 通知データと設定 |
| delegate | EditNoticesViewControllerDelegate | 入力 | 任意 | デリゲート |

## 表示項目

| 項目名 | 表示形式 | 説明 |
|--------|---------|------|
| アイコン | UIImageView | "exclamationmark.circle.fill"システムアイコン |
| タイトル | UILabel | "Edit notices" |
| サブタイトル | UILabel | "Please read before editing" |
| 通知内容 | UITextView | HTML形式の通知テキスト |
| Doneボタン | UIButton | 閉じるボタン（右上） |
| 常に表示ラベル | UILabel | "Always display edit notices" |
| 常に表示トグル | UISwitch | 設定を保存するトグル |

## イベント仕様

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

モーダルを閉じる処理。

- dismiss(animated: true)を呼び出し

### 2-常に表示トグル変更

設定を保存する処理。

- UserDefaults.standard.wmf_alwaysDisplayEditNoticesを更新

### 3-通知内リンクタップ

通知内のリンクをタップした際の処理。

- UITextViewDelegateのtextView(_:shouldInteractWith:in:interaction:)で処理
- delegate?.editNoticesControllerUserTapped(url:)を呼び出し
- モーダルを閉じた後にリンク先に遷移

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| 常に表示トグル変更 | UserDefaults | UPDATE | wmf_alwaysDisplayEditNoticesを更新 |

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

#### UserDefaults

| 操作 | 項目（キー名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | wmf_alwaysDisplayEditNotices | Bool（トグル値） | 常に編集通知を表示するか |

## メッセージ仕様

| メッセージID | 種別 | メッセージ内容 | 表示条件 |
|-------------|------|--------------|---------|
| CommonStrings.editNotices | タイトル | "Edit notices" | 常時表示 |
| edit-notices-please-read | サブタイトル | "Please read before editing" | 常時表示 |
| edit-notices-always-display | ラベル | "Always display edit notices" | 常時表示 |
| CommonStrings.doneTitle | ボタン | "Done" | 常時表示 |

## 例外処理

| 例外状況 | 処理内容 |
|---------|---------|
| 通知データが空 | 空のテキストビューが表示される |
| HTMLパースエラー | 可能な限りテキストとして表示 |

## 備考

- ThemeableViewControllerを継承
- RMessageSuppressingプロトコルに準拠（アラートメッセージを抑制）
- EditNoticesViewModelでデータを管理
- EditNoticesViewでカスタムUIを構築
- UITextViewでリンク付きHTMLを表示
- アクセシビリティ対応: UIAccessibility.postでスクリーン変更を通知
- VoiceOver対応: テキストビューの読み上げタイミングを制御

---

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

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

### 推奨読解順序

#### Step 1: ViewModelを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | EditNoticesViewModel.swift | `Wikipedia/Code/EditNoticesViewModel.swift` | siteURL、notices、semanticContentAttribute |

**主要処理フロー**:
- **7-8行目**: プロパティ定義 - siteURL、notices
- **17-19行目**: semanticContentAttribute - RTL/LTL判定

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | EditNoticesView.swift | `Wikipedia/Code/EditNoticesView.swift` | UI構造、configure()メソッド |

**主要処理フロー**:
- **7-157行目**: lazy varでUIコンポーネント定義
- **169-234行目**: setup() - AutoLayout設定
- **253-274行目**: configure(viewModel:theme:) - データとテーマ適用

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | EditNoticesViewController.swift | `Wikipedia/Code/EditNoticesViewController.swift` | 全体構造、デリゲート連携 |

**主要処理フロー**:
- **21-25行目**: init - theme、viewModelの初期化
- **31-40行目**: loadView - EditNoticesViewの生成、イベントハンドラ設定
- **42-51行目**: viewDidAppear - アクセシビリティ対応
- **55-61行目**: dismissView、didToggleSwitch - イベント処理

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

```
EditNoticesViewController
    │
    ├─ init(theme:viewModel:)
    │
    ├─ loadView()
    │      └─ EditNoticesView生成
    │             ├─ configure(viewModel:theme:)
    │             │      └─ HTMLをAttributedStringに変換
    │             ├─ doneButton.addTarget(dismissView)
    │             ├─ toggleSwitch.addTarget(didToggleSwitch)
    │             └─ textView.delegate = self
    │
    ├─ viewDidAppear()
    │      └─ UIAccessibility.post(.screenChanged)
    │         DispatchQueue.main.asyncAfter(1秒後)
    │             └─ changeTextViewVoiceOverVisibility(true)
    │
    ├─ dismissView() [Done button]
    │      └─ dismiss(animated: true)
    │
    ├─ didToggleSwitch() [Toggle switch]
    │      └─ UserDefaults.wmf_alwaysDisplayEditNotices = sender.isOn
    │
    └─ UITextViewDelegate
           └─ textView(_:shouldInteractWith:in:interaction:)
                  └─ dismiss + delegate?.editNoticesControllerUserTapped(url:)
```

### データフロー図

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

EditNoticesViewModel       EditNoticesView.configure()        UITextView
(siteURL, notices)    ───▶ HTMLをAttributedStringに変換   ───▶ (通知内容表示)

ユーザー操作                didToggleSwitch()                  UserDefaults
(トグル変更)          ───▶ wmf_alwaysDisplayEditNotices更新

リンクタップ                textView(_:shouldInteractWith:)    delegate
                      ───▶ dismiss後にURL通知              ───▶ editNoticesControllerUserTapped
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| EditNoticesViewController.swift | `Wikipedia/Code/EditNoticesViewController.swift` | ソース | メインViewController |
| EditNoticesView.swift | `Wikipedia/Code/EditNoticesView.swift` | ソース | カスタムView |
| EditNoticesViewModel.swift | `Wikipedia/Code/EditNoticesViewModel.swift` | ソース | ViewModel |
| EditNoticesFetcher.swift | `Wikipedia/Code/EditNoticesFetcher.swift` | ソース | 通知データ取得 |
| ThemeableViewController.swift | `Wikipedia/Code/ThemeableViewController.swift` | ソース | 基底クラス |
