# 画面設計書 25-InsertMediaSelectedImage画面

## 概要

本ドキュメントは、Wikipedia iOSアプリにおける選択画像プレビュー画面（InsertMediaSelectedImageViewController）の設計仕様を記載したものである。

### 本画面の処理概要

InsertMediaSelectedImage画面は、InsertMedia画面の子コンポーネントとして、ユーザーが検索結果から選択した画像のプレビューを表示する役割を担う。画面上部30%の領域に配置され、選択された画像のサムネイル、タイトル、詳細情報を表示する。

**業務上の目的・背景**：ユーザーが記事に挿入する画像を選択する際、選択した画像が意図したものであることを確認できるプレビュー機能が重要である。本画面は、検索結果グリッドから選択された画像を拡大表示し、画像の詳細情報と共に「More information」リンクを提供することで、ユーザーの画像選択を支援する。

**画面へのアクセス方法**：InsertMediaViewControllerの子ViewControllerとして自動的に表示される。単独での表示は行われない。

**主要な操作・処理内容**：
1. 検索結果コレクションで画像が選択されると自動的にプレビューを更新
2. 選択画像のダウンロードと表示
3. 「More information」リンクタップでSafariでファイルページを開く
4. 未選択状態では空状態メッセージを表示

**画面遷移**：
- 遷移元：なし（InsertMediaViewControllerの子として表示）
- 遷移先：Safari（ファイルページ）

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

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 28 | メディア挿入 | 補助機能 | 選択した画像のプレビュー表示 |

## 画面種別

プレビューコンポーネント（子ViewController）

## URL/ルーティング

iOSネイティブアプリのため、URLベースのルーティングは存在しない。InsertMediaViewControllerの子ViewControllerとして組み込まれる。

## 入出力項目

### 入力項目（delegate経由）

| 項目名 | 種別 | データ型 | 必須 | 説明 |
|--------|------|----------|------|------|
| searchResult | 入力 | InsertMediaSearchResult | 必須 | 選択された画像の検索結果情報 |

### 出力項目（プロパティ）

| 項目名 | 種別 | データ型 | 説明 |
|--------|------|----------|------|
| image | 出力 | UIImage? | 選択された画像 |
| searchResult | 出力 | InsertMediaSearchResult? | 選択された検索結果 |

## 表示項目

### 未選択状態

| 項目名 | 表示内容 | 備考 |
|--------|----------|------|
| 空状態メッセージ | "No selected image to insert" | WMFEmptyViewType.noSelectedImageToInsert |

### 選択状態

| 項目名 | 表示内容 | 備考 |
|--------|----------|------|
| 画像プレビュー | 選択された画像 | InsertMediaSelectedImageView |
| More informationリンク | ファイルページへのリンク | タップでSafari起動 |

### ローディング状態

| 項目名 | 表示内容 | 備考 |
|--------|----------|------|
| アクティビティインジケータ | ローディングスピナー | UIActivityIndicatorView.large |

## イベント仕様

### 1-画像選択

検索結果コレクションで画像がタップされると、プレビュー表示を更新する。

**処理フロー**：
1. InsertMediaSearchResultsCollectionViewControllerDelegateのdidSelectが呼び出される
2. delegate?.insertMediaSelectedImageViewController(willSetSelectedImageFrom:)で通知
3. startActivityIndicator()でローディング開始
4. searchResultからimageURL(for:)で適切なサイズのURLを取得
5. InsertMediaSelectedImageView.configure(with:searchResult:theme:)で画像をダウンロード・表示
6. 完了後、stopActivityIndicator()でローディング終了
7. delegate?.insertMediaSelectedImageViewController(didSetSelectedImage:from:)で通知

### 2-More Informationリンクタップ

ファイルページをSafariで開く。

**処理フロー**：
1. selectedView.moreInformationActionが呼び出される
2. navigate(to:useSafari:true)でSafariを起動

### 3-空状態表示

未選択状態またはエラー時に空状態を表示する。

**処理フロー**：
1. viewWillAppearで画像がnilの場合
2. wmf_showEmptyView(of: .noSelectedImageToInsert, theme:, frame:)を呼び出し
3. 画像選択時にwmf_hideEmptyView()で非表示

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

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

この画面ではローカルデータベースへの更新は行われない。

| 操作（イベント） | 対象 | 操作種別 | 概要 |
|----------------|------|---------|------|
| なし | - | - | - |

## メッセージ仕様

| ID | 種別 | メッセージ内容 | 表示条件 |
|----|------|----------------|----------|
| MSG-01 | 空状態 | "No selected image to insert" | 画像未選択時 |

## 例外処理

| 例外条件 | 処理内容 |
|----------|----------|
| 画像URL取得失敗 | stopActivityIndicator()でローディング終了、プレビュー更新なし |
| 画像ダウンロードエラー | stopActivityIndicator()でローディング終了、エラー通知なし |

## 備考

- アクティビティインジケータは0.3秒の遅延後に表示（短時間の読み込みでは表示されない）
- NSObject.cancelPreviousPerformRequestsでインジケータ表示のキャンセル処理を実装
- InsertMediaSelectedImageViewは別ファイルで定義されたカスタムビュー
- テーマ対応（Themeable）プロトコルに準拠

---

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

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

### 推奨読解順序

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

プレビュー表示に使用されるデータ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | InsertMediaSearchResult | `Wikipedia/Code/InsertMediaSearchResult.swift` | imageURL(for:)メソッド、fileTitle、displayTitle |

**読解のコツ**: imageURL(for:)メソッドが画面幅に応じた適切なサイズのURLを返すことを理解する。

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

InsertMediaSelectedImageViewControllerの構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | InsertMediaSelectedImageViewController.swift | `Wikipedia/Code/InsertMediaSelectedImageViewController.swift` | 全体構造 |

**主要処理フロー**:
1. **行1-4**: InsertMediaSelectedImageViewControllerDelegateプロトコル定義
2. **行6-18**: プロパティ定義（selectedView, activityIndicator, theme, delegate）
3. **行12-17**: image, searchResultのcomputedプロパティ（selectedViewから取得）
4. **行20-24**: viewDidLoad - テーマ適用、インジケータ配置
5. **行26-33**: viewWillAppear - 空状態表示の制御

#### Step 3: 画像選択処理を理解する

delegate実装とローディング処理を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | InsertMediaSelectedImageViewController.swift | `Wikipedia/Code/InsertMediaSelectedImageViewController.swift` | 行58-83 |

**主要処理フロー**:
- **行59-61**: delegateへの通知とローディング開始
- **行62-65**: imageURLの取得、失敗時は早期リターン
- **行66-70**: moreInformationActionの設定（初回のみ）
- **行71-82**: selectedView.configureで画像をダウンロード・表示

#### Step 4: アクティビティインジケータの制御を理解する

遅延表示とキャンセル処理を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | InsertMediaSelectedImageViewController.swift | `Wikipedia/Code/InsertMediaSelectedImageViewController.swift` | 行35-55 |

**主要処理フロー**:
- **行35-40**: startActivityIndicator - 0.3秒遅延で表示
- **行42-44**: _startActivityIndicator - 実際の表示処理
- **行46-50**: stopActivityIndicator - キャンセルと非表示
- **行52-55**: cancelPreviousActivityIndicatorSelectors - 前回リクエストのキャンセル

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

```
InsertMediaSelectedImageViewController
    │
    ├─ InsertMediaSelectedImageView
    │      ├─ image (UIImage)
    │      ├─ searchResult (InsertMediaSearchResult)
    │      ├─ moreInformationAction (URL -> Void)
    │      └─ configure(with:searchResult:theme:completion:)
    │
    ├─ UIActivityIndicatorView
    │      ├─ startAnimating()
    │      └─ stopAnimating()
    │
    ├─ WMFEmptyView
    │      ├─ wmf_showEmptyView(of:theme:frame:)
    │      └─ wmf_hideEmptyView()
    │
    └─ InsertMediaSelectedImageViewControllerDelegate
           ├─ willSetSelectedImageFrom(searchResult:)
           └─ didSetSelectedImage(selectedImage:from:)
```

### データフロー図

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

SearchResultsCollectionVC
    │
    └─ didSelect(searchResult:)
           │
           ▼
    willSetSelectedImageFrom() ──────▶ delegate通知
           │
           ▼
    startActivityIndicator() ─────▶ ローディング表示
           │
           ▼
    imageURL(for: width) ─────────▶ 適切なサイズのURL取得
           │
           ▼
    selectedView.configure()
           │
           ├─▶ 画像ダウンロード
           │
           └─▶ completion
                  │
                  ▼
           stopActivityIndicator() ──▶ ローディング非表示
                  │
                  ▼
           selectedViewをsubviewに追加
                  │
                  ▼
           didSetSelectedImage() ────▶ delegate通知
                                            │
                                            ▼
                                      image, searchResult取得可能
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| InsertMediaSelectedImageViewController.swift | `Wikipedia/Code/InsertMediaSelectedImageViewController.swift` | ソース | 本画面のコントローラ |
| InsertMediaSelectedImageView.swift | `Wikipedia/Code/InsertMediaSelectedImageView.swift` | ソース | プレビュー表示用ビュー |
| InsertMediaSearchResult.swift | `Wikipedia/Code/InsertMediaSearchResult.swift` | ソース | 検索結果データモデル |
| InsertMediaSearchResultsCollectionViewController.swift | `Wikipedia/Code/InsertMediaSearchResultsCollectionViewController.swift` | ソース | 検索結果グリッド（選択元） |
| InsertMediaViewController.swift | `Wikipedia/Code/InsertMediaViewController.swift` | ソース | 親画面（delegate実装） |
| WMFEmptyView.swift | `WMF Framework/WMFEmptyView.swift` | ソース | 空状態表示 |
| Theme.swift | `Wikipedia/Code/Theme.swift` | ソース | テーマ定義 |
