# 画面設計書 10-SearchResults画面

## 概要

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

### 本画面の処理概要

SearchResults画面は、ユーザーの検索クエリに対する検索結果をリスト表示する画面である。検索結果の選択、長押しによるプレビュー、スワイプアクションをサポートする。

**業務上の目的・背景**：ユーザーがWikipediaの記事を効率的に検索・発見できるようにする。検索結果にはタイトル、説明文、サムネイル画像が表示され、リダイレクト元情報も提供される。

**画面へのアクセス方法**：Search画面で検索クエリを入力すると表示。

**主要な操作・処理内容**：
1. 検索結果リストの表示
2. 検索結果タップによる記事画面への遷移
3. 長押しによる記事プレビュー（コンテキストメニュー）
4. スワイプアクション（保存、共有など）
5. リダイレクト元情報の表示

**画面遷移**：
- 遷移元：Search画面
- 遷移先：Article画面

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

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 4 | 検索 | 主機能 | 検索結果の表示・選択 |
| 1 | 記事閲覧 | 関連機能 | 検索結果から記事への遷移 |

## 画面種別

リスト画面（UICollectionView）

## URL/ルーティング

- エントリーポイント：Search画面の検索結果表示コンテナ
- Storyboard ID：`SearchResultsViewController`

## 入出力項目

| 項目名 | 入力/出力 | データ型 | 説明 |
|--------|----------|----------|------|
| 検索結果情報 | 入力 | WMFSearchResults | resultsInfo プロパティ（検索メタデータ） |
| 検索結果配列 | 入力 | [MWKSearchResult] | results プロパティ（結果リスト） |
| 検索サイトURL | 入力 | URL | searchSiteURL プロパティ（検索対象Wikipedia） |
| タップアクション | 入力 | ((URL, IndexPath) -> Void)? | tappedSearchResultAction クロージャ |
| 長押しコミットアクション | 入力 | ((URL) -> Void)? | longPressSearchResultAndCommitAction クロージャ |
| 新規タブアクション | 入力 | ((URL) -> Void)? | longPressOpenInNewTabAction クロージャ |

## 表示項目

| 項目名 | データソース | 表示条件 | 備考 |
|--------|-------------|----------|------|
| 検索結果セル | ArticleRightAlignedImageCollectionViewCell | 結果あり | 右側にサムネイル配置 |
| タイトル | result.displayTitleHTML | 常時 | 検索語をボールド表示 |
| 説明文 | descriptionForSearchResult | 常時 | Wikidata説明 + リダイレクト情報 |
| サムネイル画像 | result.thumbnailURL | URLあり | 右側に配置 |
| 空状態 | updateEmptyState | 結果なし | 結果が空の場合 |

## イベント仕様

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

`collectionView(_:didSelectItemAt:)`で検索結果をタップすると、`tappedSearchResultAction`クロージャが呼び出され、親コントローラ（SearchViewController）が記事画面へ遷移を処理。

**ソースコード参照**: SearchResultsViewController.swift 行58-65（collectionView:didSelectItemAt:）

### 2-長押しプレビューコミット

`collectionView(_:willPerformPreviewActionForMenuWith:animator:)`でコンテキストメニューからのコミット操作を処理。ArticlePeekPreviewViewControllerから記事URLを取得し、`longPressSearchResultAndCommitAction`を呼び出す。

**ソースコード参照**: SearchResultsViewController.swift 行147-159（willPerformPreviewActionForMenuWith）

### 3-「続きを読む」アクション

`readMoreArticlePreviewActionSelected`で長押しメニューから「続きを読む」を選択した場合、`longPressSearchResultAndCommitAction`を呼び出して記事画面へ遷移。

**ソースコード参照**: SearchResultsViewController.swift 行161-164（readMoreArticlePreviewActionSelected）

### 4-新規タブで開くアクション

`openInNewTabArticlePreviewActionSelected`で長押しメニューから「新規タブで開く」を選択した場合、`longPressOpenInNewTabAction`を呼び出す。

**ソースコード参照**: SearchResultsViewController.swift 行166-168（openInNewTabArticlePreviewActionSelected）

### 5-記事更新通知

`updateArticleCell`メソッドが`WMFArticleUpdated`通知を監視し、保存状態などの変更時にセルを再描画。

**ソースコード参照**: SearchResultsViewController.swift 行19, 130-145（updateArticleCell）

### 6-セル設定

`configure(cell:forItemAt:layoutOnly:)`で各セルにタイトル、説明文、画像を設定。検索語のボールド表示、リダイレクト情報の表示、言語別のセマンティック属性設定を行う。

**ソースコード参照**: SearchResultsViewController.swift 行90-120（configure）

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| 記事取得 | WMFArticle | UPSERT | fetchOrCreateArticle で記事をキャッシュ |

## メッセージ仕様

| メッセージID | メッセージ内容 | 表示条件 | 種別 |
|-------------|---------------|----------|------|
| search-result-redirected-from | Redirected from: %1$@ | リダイレクト時 | 情報 |

## 例外処理

- **検索結果なし**：`updateEmptyState()`で空状態を表示
- **インデックス範囲外**：`configure`でindexPath.item < results.countをチェック
- **URL取得失敗**：`collectionView:didSelectItemAt`でURLがnilの場合、選択解除のみ

## 備考

- SearchResultsViewControllerはArticleCollectionViewControllerを継承
- イベントログカテゴリは`.search`に設定
- MWKSearchResult.displayTitleHTMLで検索語をボールド表示
- リダイレクト元情報はWMFSearchResults.redirectMappingsから取得
- configureForCompactListでコンパクトリスト表示に対応
- テーマ対応でmidBackgroundカラーを使用

---

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

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

### 推奨読解順序

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

検索結果のデータモデルを理解。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | MWKSearchResult | `Wikipedia/Code/` | 検索結果モデル（displayTitleHTML, thumbnailURL等） |
| 1-2 | WMFSearchResults | `WMF Framework/` | 検索メタデータ（searchTerm, redirectMappings等） |
| 1-3 | MWKSearchRedirectMapping | `Wikipedia/Code/` | リダイレクトマッピング構造 |

**読解のコツ**: MWKSearchResultが持つ各プロパティとWMFSearchResultsの関係を把握。

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

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

**主要処理フロー**:
1. **行6-11 results didSet**: 検索結果設定時にreload()を呼び出し
2. **行16-20 viewDidLoad**: 初期化と記事更新通知の監視登録
3. **行54-65 collectionView:didSelectItemAt**: タップ処理とアクション呼び出し
4. **行90-120 configure**: セル設定、タイトルHTML、説明文、画像

#### Step 3: 親クラスを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | ArticleCollectionViewController.swift | `Wikipedia/Code/` | 基底クラスの機能（スワイプアクション、編集コントローラ） |

#### Step 4: 呼び出し元を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | SearchViewController.swift | `Wikipedia/Code/` | 検索結果の表示制御、アクションクロージャの設定 |

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

```
SearchViewController
    │
    └─ SearchResultsViewController (extends ArticleCollectionViewController)
           │
           ├─ resultsInfo: WMFSearchResults
           │      ├─ searchTerm
           │      └─ redirectMappings[]
           │
           ├─ results: [MWKSearchResult]
           │      ├─ displayTitleHTML
           │      ├─ wikidataDescription
           │      └─ thumbnailURL
           │
           ├─ Action Closures
           │      ├─ tappedSearchResultAction
           │      ├─ longPressSearchResultAndCommitAction
           │      └─ longPressOpenInNewTabAction
           │
           └─ ArticleRightAlignedImageCollectionViewCell
                  ├─ titleLabel (HTML with bold search term)
                  ├─ descriptionLabel (redirect info + description)
                  └─ imageView (thumbnail)
```

### データフロー図

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

Search Query ───▶ SearchViewController ───▶ API Search
                         │
                         ▼
WMFSearchResults ──▶ SearchResultsViewController
results[] ──────────│
                    │
                    ▼
              collectionView.reloadData()
                    │
                    ▼
              configure(cell:) ───▶ Display Cell
                    │
                    ├──▶ setTitleHTML (bold search term)
                    ├──▶ descriptionForSearchResult (redirect + description)
                    └──▶ imageURL (thumbnail)

User Tap ────────▶ didSelectItemAt ───▶ tappedSearchResultAction
                         │
                         ▼
                  SearchViewController
                         │
                         ▼
                  Article画面 Navigation
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| SearchResultsViewController.swift | `Wikipedia/Code/` | ソース | メインViewController（169行） |
| ArticleCollectionViewController.swift | `Wikipedia/Code/` | ソース | 基底クラス |
| MWKSearchResult.swift | `Wikipedia/Code/` | ソース | 検索結果モデル |
| WMFSearchResults | `WMF Framework/` | ソース | 検索メタデータ |
| MWKSearchRedirectMapping | `Wikipedia/Code/` | ソース | リダイレクトマッピング |
| ArticleRightAlignedImageCollectionViewCell | `Wikipedia/Code/` | ソース | 検索結果セル |
| SearchViewController.swift | `Wikipedia/Code/` | ソース | 親コントローラ（743行） |
| ArticlePeekPreviewViewController.swift | `Wikipedia/Code/` | ソース | 長押しプレビュー |
