# 画面設計書 4-Search画面

## 概要

本ドキュメントは、Wikipedia iOSアプリのSearch画面の設計仕様を記載したものである。

### 本画面の処理概要

Search画面は、Wikipediaの記事を検索するための画面である。検索バーへの入力に応じてリアルタイムで検索結果を表示し、最近検索した用語の履歴も管理する。

**業務上の目的・背景**：ユーザーがWikipediaの膨大な記事から目的のコンテンツを素早く見つけられるようにする。プレフィックス検索とフルテキスト検索を組み合わせ、精度の高い検索結果を提供。多言語検索にも対応し、言語バーで検索対象言語を切り替え可能。

**画面へのアクセス方法**：タブバーの4番目の項目（Search）をタップ、またはExplore/Article画面のナビゲーションバー検索アイコンから。

**主要な操作・処理内容**：
1. 検索テキストの入力とリアルタイム検索
2. 検索結果のタップによる記事画面への遷移
3. 検索履歴の表示と選択
4. 検索履歴のクリア
5. 検索言語の切り替え（言語バー）
6. プロファイル・タブボタンからの画面遷移

**画面遷移**：
- 遷移元：タブバー、Explore画面、Article画面
- 遷移先：Article画面、プロファイル画面、タブ一覧画面

**権限による表示制御**：ログイン状態によりプロファイルボタンの表示内容が変化。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 11 | 記事検索 | 主機能 | プレフィックス検索、フルテキスト検索の実行 |
| 12 | 多言語検索 | 主機能 | 言語バーによる検索対象言語の切り替え |
| 44 | プロファイル画面 | 遷移先機能 | プロファイルボタンタップでプロファイル画面へ遷移 |
| 61 | タブ一覧 | 遷移先機能 | タブボタンタップでタブ一覧画面へ遷移 |

## 画面種別

一覧（検索結果）

## URL/ルーティング

- エントリーポイント：タブバー経由、またはナビゲーションバー検索
- Storyboard ID：`SearchViewController`
- Objective-C名：`WMFSearchViewController`

## 入出力項目

| 項目名 | 入力/出力 | データ型 | 説明 |
|--------|----------|----------|------|
| 検索テキスト | 入力 | String | searchTerm プロパティ |
| 検索言語 | 入力 | URL | siteURL プロパティ |
| 検索結果 | 出力 | [WMFSearchResult] | WMFSearchResults.results |
| 最近の検索 | 出力 | [MWKRecentSearchEntry] | recentSearches配列 |

## 表示項目

| 項目名 | データソース | 表示条件 | 備考 |
|--------|-------------|----------|------|
| 検索バー | - | 常時 | UISearchController使用 |
| 言語バー | SearchLanguagesBarViewController | showLanguageBar設定時 | 言語切替用 |
| 最近の検索リスト | MWKRecentSearchList | 検索前・検索テキスト空時 | WMFRecentlySearchedView (SwiftUI) |
| 検索結果リスト | WMFSearchResults | 検索テキスト入力時 | SearchResultsViewController |

## イベント仕様

### 1-検索テキスト入力

検索バーにテキストを入力すると、`UISearchResultsUpdating`の`updateSearchResults`メソッドが呼び出される。`search(for:suggested:)`メソッドで検索を実行し、`WMFSearchFetcher`を通じてWikipedia APIにリクエスト。

**ソースコード参照**: SearchViewController.swift 行355-420（search関数）

### 2-検索結果タップ

`SearchResultsViewController`のセルタップで`tappedSearchResultAction`クロージャが実行される。`saveLastSearch()`で検索履歴を保存し、`ArticleCoordinator`または`LinkCoordinator`で記事画面へ遷移。

**ソースコード参照**: SearchViewController.swift 行447-480（tappedSearchResultAction）

### 3-最近の検索選択

`WMFRecentlySearchedView`のアイテムタップで`selectAction`クロージャが実行される。検索バーにテキストを設定し、`search()`メソッドで検索を再実行。

**ソースコード参照**: SearchViewController.swift 行578-588（selectAction）

### 4-検索履歴クリア

「Clear」ボタンタップで`didPressClearRecentSearches`クロージャが実行。UIAlertControllerで確認後、`deleteAllAction`で全履歴を削除。

**ソースコード参照**: SearchViewController.swift 行536-543（didPressClearRecentSearches）

### 5-言語切替

`SearchLanguagesBarViewController`で言語を選択すると、`searchLanguagesBarViewController(_:didChangeSelectedSearchContentLanguageCode:)`デリゲートメソッドが呼び出され、`search()`で再検索。

**ソースコード参照**: SearchViewController.swift 行663-667

### 6-プロファイルボタンタップ

ナビゲーションバーのプロファイルボタンタップで`userDidTapProfile`メソッドが呼び出され、`ProfileCoordinator.start()`でプロファイル画面へ遷移。

**ソースコード参照**: SearchViewController.swift 行238-252

### 7-タブボタンタップ

タブアイコンタップで`userDidTapTabs`メソッドが呼び出され、`TabsOverviewCoordinator.start()`でタブ一覧画面へ遷移。

**ソースコード参照**: SearchViewController.swift 行254-257

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| 検索履歴保存 | MWKRecentSearchEntry | INSERT | 検索用語の履歴保存 |
| 検索履歴削除 | MWKRecentSearchEntry | DELETE | 個別または全削除 |

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

#### MWKRecentSearchEntry

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | searchTerm, siteURL | 検索実行時の値 | 履歴追加 |
| DELETE | - | 全件または個別 | 履歴クリア |

## メッセージ仕様

| メッセージID | メッセージ内容 | 表示条件 | 種別 |
|-------------|---------------|----------|------|
| search-no-results | No results found | 検索結果0件時 | 情報 |
| search-no-internet | No internet connection | ネットワークエラー時 | エラー |
| clear-recent-searches-title | Clear recent searches? | 履歴クリア確認 | 確認 |

## 例外処理

- **ネットワークエラー**：`emptyViewType = .noInternetConnection`で接続エラービューを表示
- **検索結果なし**：`emptyViewType = .noSearchResults`で結果なしビューを表示
- **無効な入力**：空白のみの入力は検索実行しない（`wmf_hasNonWhitespaceText`でチェック）

## 備考

- SearchViewControllerはThemeableViewControllerを継承
- WMFNavigationBarConfiguring、WMFNavigationBarHidingプロトコルに準拠
- 検索履歴はMWKRecentSearchListで管理（最大15件程度）
- 最近の検索UIはSwiftUIのWMFRecentlySearchedViewで実装
- 検索結果が12件未満の場合、フルテキスト検索も追加実行

---

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

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

### 推奨読解順序

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

検索関連のデータモデルを理解。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | WMFSearchResults.swift | `WMF/Sources/WMF/Search/WMFSearchResults.swift` | 検索結果コンテナ、results配列 |
| 1-2 | MWKRecentSearchEntry.swift | `WMF/Sources/WMF/Search/MWKRecentSearchEntry.swift` | 検索履歴エントリ |
| 1-3 | MWKRecentSearchList.swift | `WMF/Sources/WMF/Search/MWKRecentSearchList.swift` | 検索履歴リスト管理 |

**読解のコツ**: WMFSearchResultsはWikipedia APIのレスポンスを直接マッピング。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | SearchViewController.swift | `Wikipedia/Code/SearchViewController.swift` | 行123-128 viewDidLoad、行130-152 viewWillAppear/viewDidAppear |

**主要処理フロー**:
1. **行123 viewDidLoad**: embedRecentSearches()、embedResultsViewController()、updateLanguageBarVisibility()
2. **行130 viewWillAppear**: configureNavigationBar()、reloadRecentSearches()
3. **行137 viewDidAppear**: SearchFunnel.logSearchStart()

#### Step 3: 検索ロジック層を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | WMFSearchFetcher.swift | `WMF/Sources/WMF/Search/WMFSearchFetcher.swift` | Wikipedia検索APIの呼び出し |
| 3-2 | SearchFunnel.swift | `Wikipedia/Code/Analytics/SearchFunnel.swift` | 検索アナリティクス |

**検索フロー詳細**:
1. プレフィックス検索を実行（行407-410）
2. 結果が12件未満の場合、フルテキスト検索も追加実行（行411-418）

#### Step 4: UI表示層を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | SearchResultsViewController.swift | `Wikipedia/Code/SearchResultsViewController.swift` | 検索結果の表示 |
| 4-2 | WMFRecentlySearchedView.swift | `WMFComponents/Sources/.../WMFRecentlySearchedView.swift` | 最近の検索UI (SwiftUI) |
| 4-3 | SearchLanguagesBarViewController.swift | `Wikipedia/Code/SearchLanguagesBarViewController.swift` | 言語切替バー |

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

```
SearchViewController
    │
    ├─ UISearchController (navigation bar)
    │      └─ UISearchBar
    │
    ├─ WMFRecentlySearchedView (SwiftUI)
    │      └─ WMFRecentlySearchedViewModel
    │
    ├─ SearchResultsViewController
    │      └─ UICollectionView
    │
    ├─ SearchLanguagesBarViewController
    │      └─ Language selection
    │
    ├─ WMFSearchFetcher
    │      └─ Wikipedia Search API
    │
    ├─ MWKRecentSearchList
    │      └─ UserDefaults persistence
    │
    ├─ ProfileCoordinator
    │      └─ ProfileViewController
    │
    └─ TabsOverviewCoordinator
           └─ TabsOverviewViewController
```

### データフロー図

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

Search Text ───────▶ WMFSearchFetcher ───▶ API Request
                           │
                           ▼
API Response ─────────▶ WMFSearchResults
                           │
                           ▼
                    SearchResultsViewController ───▶ CollectionView
                           │
Result Tap ───────────▶ saveLastSearch() ───▶ MWKRecentSearchList
                           │
                           ▼
                    ArticleCoordinator ───▶ ArticleViewController
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| SearchViewController.swift | `Wikipedia/Code/SearchViewController.swift` | ソース | メインViewController（743行） |
| SearchResultsViewController.swift | `Wikipedia/Code/SearchResultsViewController.swift` | ソース | 検索結果表示 |
| WMFSearchFetcher.swift | `WMF/Sources/WMF/Search/WMFSearchFetcher.swift` | ソース | 検索API呼び出し |
| WMFSearchResults.swift | `WMF/Sources/WMF/Search/WMFSearchResults.swift` | ソース | 検索結果モデル |
| MWKRecentSearchList.swift | `WMF/Sources/WMF/Search/MWKRecentSearchList.swift` | ソース | 検索履歴管理 |
| MWKRecentSearchEntry.swift | `WMF/Sources/WMF/Search/MWKRecentSearchEntry.swift` | ソース | 履歴エントリモデル |
| WMFRecentlySearchedView.swift | `WMFComponents/Sources/` | ソース | 最近の検索UI |
| SearchLanguagesBarViewController.swift | `Wikipedia/Code/` | ソース | 言語バー |
| ProfileCoordinator.swift | `Wikipedia/Code/` | ソース | プロファイル遷移 |
| ArticleCoordinator.swift | `Wikipedia/Code/` | ソース | 記事遷移 |
