# 画面設計書 23-InsertMediaSearch画面

## 概要

本ドキュメントは、Wikipedia iOSアプリにおけるメディア検索機能の画面（InsertMediaSearchViewController）の設計仕様を記載したものである。

### 本画面の処理概要

InsertMediaSearch画面は、InsertMedia画面の子コンポーネントとして、Wikimedia Commonsから画像を検索するための検索バーUIと検索ロジックを提供する。ユーザーが入力したキーワードに基づいてCommonsの画像ファイルを検索し、結果を親画面に通知する役割を担う。

**業務上の目的・背景**：Wikipedia記事に挿入する画像を探す際、ユーザーは関連するキーワードで効率的に検索できる必要がある。本画面は、Wikimedia Commonsの膨大な画像ライブラリから適切な画像を見つけるための検索インターフェースを提供し、記事編集の効率化を支援する。

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

**主要な操作・処理内容**：
1. 検索バーにキーワードを入力する
2. 入力に応じてリアルタイムで検索が実行される
3. 検索結果がdelegateを通じて親画面に通知される
4. 各検索結果の画像情報（MWKImageInfo）を非同期で取得
5. 検索バーのReturnキーで検索バーを閉じる

**画面遷移**：
- 遷移元：なし（InsertMediaViewControllerの子として表示）
- 遷移先：なし（検索結果は親画面で処理）

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

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 28 | メディア挿入 | 補助機能 | Commonsから画像を検索するUIを提供 |

## 画面種別

検索コンポーネント（子ViewController）

## URL/ルーティング

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

## 入出力項目

### 入力項目

| 項目名 | 種別 | データ型 | 必須 | 説明 |
|--------|------|----------|------|------|
| articleTitle | 入力 | String? | 任意 | 編集中の記事タイトル（プレースホルダーおよび初期検索ワードとして使用） |
| siteURL | 入力 | URL? | 任意 | WikipediaサイトのURL（nilの場合はCommons APIを使用） |

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

| 項目名 | 種別 | データ型 | 説明 |
|--------|------|----------|------|
| searchResults | 出力 | [InsertMediaSearchResult] | 検索結果の配列 |
| imageInfo | 出力 | MWKImageInfo | 各検索結果の詳細画像情報 |
| error | 出力 | Error | 検索失敗時のエラー情報 |

## 表示項目

### 検索バー

| 項目名 | 表示内容 | 備考 |
|--------|----------|------|
| プレースホルダー | 記事タイトルまたは"Search" | articleTitle ?? CommonStrings.searchTitle |
| スタイル | minimal | searchBarStyle = .minimal |
| Returnキー | Done | returnKeyType = .done |
| Returnキー有効化 | 常に有効 | enablesReturnKeyAutomatically = false |

## イベント仕様

### 1-検索テキスト変更

ユーザーが検索バーに文字を入力するたびに検索が実行される。

**処理フロー**：
1. searchBarDelegateのtextDidChangeが呼び出される（親VCで設定）
2. search(for:)メソッドが呼び出される
3. 前回の検索をキャンセル（cancelAllFetches）
4. 空白のみの場合は記事タイトルで再検索
5. WMFSearchFetcherでファイル検索を実行
6. 結果をInsertMediaSearchResultに変換
7. delegateにdidFind(searchResults:)で通知
8. 各結果に対してMWKImageInfoFetcherで詳細情報を取得
9. delegateにdidFind(imageInfo:for:at:)で通知

**検索ロジックの詳細**：
```
1. 通常検索（fullTextSearch: false）を実行
2. 結果が0件 → フルテキスト検索を実行
3. 結果が12件未満 → 既存結果を先に通知 + フルテキスト検索を追加実行
4. 結果が12件以上 → そのまま結果を使用
```

### 2-検索ボタンタップ（キーボードのReturn）

キーボードのReturnボタンをタップすると、検索バーのキーボードが閉じる。

**処理フロー**：
1. searchBarDelegateのsearchBarSearchButtonClickedが呼び出される
2. searchBar.endEditing(true)でキーボードを閉じる

### 3-記事タイトルでの自動検索

viewDidLoad時に記事タイトルが設定されている場合、自動的に検索を実行する。

**処理フロー**：
1. viewDidLoadが呼び出される
2. articleTitleがnilでない場合、search(for: articleTitle, isFirstSearch: true)を実行
3. 検索バーのプレースホルダーにarticleTitleを設定

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

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

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

| 操作（イベント） | 対象 | 操作種別 | 概要 |
|----------------|------|---------|------|
| 検索実行 | Wikimedia Commons API | SELECT | ファイル検索クエリの送信 |
| 画像情報取得 | Wikimedia Commons API | SELECT | 画像の詳細情報取得 |

## メッセージ仕様

| ID | 種別 | メッセージ内容 | 表示条件 |
|----|------|----------------|----------|
| - | - | この画面では直接メッセージを表示しない（親画面で表示） | - |

## 例外処理

| 例外条件 | 処理内容 |
|----------|----------|
| 検索エラー | delegateにdidFailWithError(error:)で通知 |
| 空白のみの入力 | 記事タイトルで再検索を実行 |
| siteURLがnil | Commons APIのデフォルトURLを使用 |

## 備考

- 検索はWMFSearchFetcherとMWKImageInfoFetcherの2つのフェッチャーを使用
- シングルトンパターンを使用したデータストア参照があり（SINGLETONTODO コメント）、リファクタリングの候補
- 検索結果の変換時に、fileTitleから"File:"プレフィックスを除去してdisplayTitleを生成

---

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

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

### 推奨読解順序

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

検索結果のデータ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | InsertMediaSearchResult | `Wikipedia/Code/InsertMediaSearchResult.swift` | fileTitle, displayTitle, thumbnailURL, imageInfoの構造 |
| 1-2 | MWKImageInfo | `WMF Framework/MWKImageInfo.h` | 画像の詳細情報構造 |

**読解のコツ**: fileTitleは"File:xxx.jpg"形式、displayTitleは"xxx"形式であることに注意。

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

InsertMediaSearchViewControllerの初期化と検索ロジックを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | InsertMediaSearchViewController.swift | `Wikipedia/Code/InsertMediaSearchViewController.swift` | メインクラス全体 |

**主要処理フロー**:
1. **行1-5**: InsertMediaSearchViewControllerDelegateプロトコル定義
2. **行7-17**: プロパティ定義（searchBar, fetchers, delegate等）
3. **行22-26**: init - articleTitleとsiteURLの設定
4. **行32-44**: viewDidLoad - 検索バーの設定と初期検索
5. **行46-116**: search(for:isFirstSearch:) - 検索ロジックの中核

#### Step 3: 検索ロジックの詳細を理解する

search(for:)メソッドの検索戦略を理解する。

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

**主要処理フロー**:
- **行47-48**: 前回の検索をキャンセル
- **行49-52**: 空白入力時は記事タイトルで再検索
- **行54-58**: エラーハンドリングクロージャ
- **行59-76**: 検索結果の変換ロジック
- **行77-98**: 成功時の処理（delegate通知 + 画像情報取得）
- **行99-115**: 検索実行と結果数に応じた追加検索

#### Step 4: delegateパターンを理解する

親ViewControllerとの連携方法を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | InsertMediaViewController.swift | `Wikipedia/Code/InsertMediaViewController.swift` | 行166-189のextension |

**主要処理フロー**:
- **行167-170**: didFind(searchResults:) - 検索結果の受け取り
- **行172-174**: didFind(imageInfo:for:at:) - 画像情報の受け取り
- **行176-188**: didFailWithError - エラー処理

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

```
InsertMediaSearchViewController
    │
    ├─ UISearchBar
    │      └─ searchBarDelegate (親VCが設定)
    │
    ├─ WMFSearchFetcher
    │      │
    │      ├─ fetchFiles(forSearchTerm:...) [通常検索]
    │      │
    │      └─ fetchFiles(forSearchTerm:fullTextSearch:true:...) [フルテキスト]
    │
    ├─ MWKImageInfoFetcher
    │      └─ fetchGalleryInfo(forImage:fromSiteURL:...)
    │
    └─ InsertMediaSearchViewControllerDelegate
           ├─ didFind(searchResults:)
           ├─ didFind(imageInfo:for:at:)
           └─ didFailWithError(error:)
```

### データフロー図

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

ユーザー入力 ──────────▶ search(for:)
                              │
                              ├─▶ WMFSearchFetcher
                              │        │
                              │        ├─▶ 通常検索
                              │        │        │
                              │        │        ├─▶ 0件: フルテキスト検索
                              │        │        ├─▶ <12件: 先に通知+フルテキスト追加
                              │        │        └─▶ >=12件: そのまま使用
                              │        │
                              │        └─▶ WMFSearchResults
                              │                 │
                              │                 ▼
                              │        [InsertMediaSearchResult]
                              │                 │
                              ├─▶ MWKImageInfoFetcher
                              │        │
                              │        └─▶ MWKImageInfo (各結果に対して)
                              │
                              └─▶ Delegate通知
                                       │
                                       ├─▶ didFind(searchResults:)
                                       ├─▶ didFind(imageInfo:for:at:)
                                       └─▶ didFailWithError(error:)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| InsertMediaSearchViewController.swift | `Wikipedia/Code/InsertMediaSearchViewController.swift` | ソース | 本画面のコントローラ |
| InsertMediaSearchResult.swift | `Wikipedia/Code/InsertMediaSearchResult.swift` | ソース | 検索結果データモデル |
| InsertMediaViewController.swift | `Wikipedia/Code/InsertMediaViewController.swift` | ソース | 親画面（delegate実装） |
| WMFSearchFetcher.swift | `WMF Framework/WMFSearchFetcher.swift` | ソース | 検索API呼び出し |
| MWKImageInfoFetcher.swift | `WMF Framework/MWKImageInfoFetcher.swift` | ソース | 画像情報API呼び出し |
| MWKImageInfo.h | `WMF Framework/MWKImageInfo.h` | ソース | 画像情報データモデル |
| Theme.swift | `Wikipedia/Code/Theme.swift` | ソース | テーマ定義 |
| CommonStrings.swift | `WMF Framework/CommonStrings.swift` | ソース | 共通文字列定義 |
