# 画面設計書 78-ArticleCollectionViewController画面

## 概要

本ドキュメントは、Wikipedia iOSアプリの記事コレクション表示の基底クラス（ArticleCollectionViewController）の設計を記述したものである。

### 本画面の処理概要

ArticleCollectionViewControllerは、Wikipedia記事のリスト表示を行う画面の共通基盤を提供する基底クラスである。ColumnarCollectionViewControllerを継承し、記事に特化した機能（記事セルの表示、スワイプアクション、保存/共有機能、コンテキストメニュー）を追加している。

**業務上の目的・背景**：Wikipediaアプリには、検索結果、保存済み記事、閲覧履歴、リーディングリスト詳細など、記事のリストを表示する多くの画面が存在する。これらの画面は記事データの表示とユーザーインタラクション（保存、共有、削除等）において共通の機能を持つため、ArticleCollectionViewControllerとして共通ロジックを集約している。これにより、コードの重複を排除し、記事リスト表示の一貫した体験を提供する。

**画面へのアクセス方法**：本クラスは基底クラスであり、直接表示されることはない。ArticleFetchedResultsViewController、ArticleURLListViewController、ReadingListEntryCollectionViewControllerなど、多くのViewControllerがこのクラスを継承している。

**主要な操作・処理内容**：
1. ArticleRightAlignedImageCollectionViewCellを使用した記事リスト表示
2. EditControllerを使用したスワイプアクション（保存、共有、削除）
3. 記事セルタップで記事詳細画面への遷移
4. コンテキストメニュー（長押し）で記事プレビュー表示
5. 記事の保存/保存解除操作
6. 記事の共有機能
7. イベントログ記録のサポート

**画面遷移**：
- 本クラスは基底クラスであり、直接的な画面遷移元はない
- セル選択時：ArticleCoordinatorを通じてArticle画面へ遷移
- コンテキストメニューからの遷移：ArticlePeekPreviewViewControllerを経由してArticle画面へ遷移

**権限による表示制御**：特になし。継承先で必要に応じて実装される。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 1 | 記事表示 | 補助機能 | 記事コレクション表示の共通基盤 |

## 画面種別

基底クラス（画面なし）

## URL/ルーティング

本クラスは基底クラスであり、ルーティングは適用されない。

## 入出力項目

| 項目名 | 型 | 入力/出力 | 説明 |
|--------|-----|----------|------|
| dataStore | MWKDataStore | 入力 | データストアインスタンス |
| contentGroup | WMFContentGroup? | 入力 | コンテンツグループ（オプション） |
| articleSource | ArticleSource | 入力 | 記事ソース識別（デフォルト: .undefined） |

## 表示項目

| 項目名 | データソース | 説明 |
|--------|-------------|------|
| 記事セル | ArticleRightAlignedImageCollectionViewCell | 記事表示用セル |
| サムネイル画像 | WMFArticle.imageURL | 記事のサムネイル |
| タイトル | WMFArticle.displayTitle | 記事のタイトル |
| 説明文 | WMFArticle.wikidataDescription | 記事の概要説明 |
| セパレータ | - | セル間の区切り線 |

## イベント仕様

### 1-セル選択（didSelectItemAt）

記事セルをタップすると、ArticleCoordinatorを生成してstart()を呼び出し、Article画面へ遷移する。

### 2-スワイプアクション

EditControllerを通じて以下のスワイプアクションを提供：
- **保存（Save）**: 記事をリーディングリストに保存
- **保存解除（Unsave）**: 保存済み記事を解除
- **共有（Share）**: 記事を共有
- **削除（Delete）**: 記事を削除（サブクラスで実装）

### 3-コンテキストメニュー

記事セルを長押しすると、ArticlePeekPreviewViewControllerによるプレビューを表示。プレビューからの操作（読む、保存、共有等）に対応。

### 4-セル表示終了（didEndDisplaying）

セルが画面外に出ると、editController.deconfigureSwipeableCell()を呼び出してスワイプ状態をリセット。

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| 記事保存 | SavedPageList | INSERT | 記事をリーディングリストに追加 |
| 記事保存解除 | SavedPageList | DELETE | 記事をリーディングリストから削除 |
| 記事削除 | WMFArticle | DELETE | 記事を履歴等から削除（サブクラスで実装） |

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

#### SavedPageList

| 操作 | 項目 | 更新値・取得条件 | 備考 |
|-----|------|-----------------|------|
| INSERT | articleURL | 保存対象の記事URL | addSavedPage(with:)で追加 |
| DELETE | articleURL | 解除対象の記事URL | removeEntry(with:)で削除 |

## メッセージ仕様

| メッセージID | 種別 | 表示条件 | メッセージ内容 |
|-------------|------|---------|---------------|
| articleDeletedNotification | アクセシビリティ | 削除操作後 | 削除完了通知 |
| accessibilitySavedNotification | アクセシビリティ | 保存操作後 | 保存完了通知 |
| accessibilityUnsavedNotification | アクセシビリティ | 保存解除後 | 保存解除完了通知 |

## 例外処理

| 例外ケース | 処理内容 |
|-----------|---------|
| article(at:)がnilを返す | 処理をスキップ |
| articleURL(at:)がnilを返す | セル選択をデセレクトして終了 |
| 保存済み記事の保存解除確認 | ReadingListsAlertControllerでアラート表示 |

## 備考

- ColumnarCollectionViewControllerを継承
- EditableCollection、MEPEventsProviding、CollectionViewContextMenuShowingプロトコルを実装
- EditControllerを使用してスワイプアクションを管理
- articleSource（ArticleSource）で記事の取得元を識別
- cellLayoutEstimateでセルの高さ推定値をキャッシュ（Dynamic Type変更時にリセット）
- ShareableArticlesProviderを拡張で実装し、共有機能をサポート

---

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

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

### 推奨読解順序

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

まず、記事データとアクション関連のデータ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | WMFArticle | `WMF Framework/Core Data/` | 記事データモデル |
| 1-2 | Action | `Wikipedia/Code/` | スワイプアクションの定義 |
| 1-3 | EditController | `Wikipedia/Code/` | スワイプ編集コントローラー |

**読解のコツ**: ActionTypeは.save, .unsave, .share, .deleteの4種類があり、それぞれのアクションに対応する処理がActionDelegateで定義される。

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

処理の起点となるファイル・関数を特定する。

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

**主要処理フロー**:
1. **行15-24**: viewDidLoadでセル登録とEditController設定
2. **行26-35**: configure(cell:forItemAt:layoutOnly:)でセルを設定
3. **行174-183**: didSelectItemAtで記事画面へ遷移
4. **行215-242**: didPerformAction()でスワイプアクションを処理

#### Step 3: スワイプアクションを理解する

EditControllerとActionDelegateの連携を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | ArticleCollectionViewController.swift | `Wikipedia/Code/ArticleCollectionViewController.swift` | ActionDelegate実装 |

**主要処理フロー**:
- **行244-262**: availableActions(at:)で利用可能なアクションを返す
- **行196-213**: willPerformAction()でアクション実行前の確認（保存解除時のアラート等）
- **行215-242**: didPerformAction()で実際のアクション処理

#### Step 4: コンテキストメニューを理解する

長押しプレビューの実装を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | ArticleCollectionViewController.swift | `Wikipedia/Code/ArticleCollectionViewController.swift` | CollectionViewContextMenuShowing実装 |

**主要処理フロー**:
- **行137-146**: previewingViewController(for:at:)でArticlePeekPreviewViewControllerを生成

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

```
ArticleCollectionViewController
    │
    ├─ viewDidLoad() [行15-24]
    │      ├─ layoutManager.register(ArticleRightAlignedImageCollectionViewCell)
    │      └─ setupEditController()
    │
    ├─ configure(cell:forItemAt:layoutOnly:) [行26-35]
    │      ├─ article(at:) [行56-59]
    │      ├─ cell.configure(article:displayType:...)
    │      └─ editController.configureSwipeableCell()
    │
    ├─ collectionView(_:didSelectItemAt:) [行174-183]
    │      ├─ articleURL(at:)
    │      └─ ArticleCoordinator.start()
    │
    ├─ previewingViewController(for:at:) [行137-146]
    │      └─ ArticlePeekPreviewViewController()
    │
    └─ ActionDelegate実装 [行190-263]
           ├─ willPerformAction() [行196-213]
           ├─ didPerformAction() [行215-242]
           │      ├─ delete(at:)
           │      ├─ dataStore.savedPageList.addSavedPage()
           │      ├─ dataStore.savedPageList.removeEntry()
           │      └─ share()
           └─ availableActions(at:) [行244-262]
```

### データフロー図

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

dataStore ───────────▶ article(at:)
    │                        │
    │                        ▼
    │               WMFArticle取得
    │                        │
    │                        ▼
    │               configure(cell:...)
    │                        │
    └──────────────────────▶ ▼
                    ArticleRightAlignedImage
                    CollectionViewCell
                           │
           ┌───────────────┼───────────────┐
           │               │               │
           ▼               ▼               ▼
        タップ          スワイプ        長押し
           │               │               │
           ▼               ▼               ▼
    ArticleCoordinator  ActionDelegate   ArticlePeek
       .start()       .didPerformAction() PreviewVC
           │               │               │
           ▼               │               ▼
      Article画面    ┌─────┼─────┐     プレビュー
                     │     │     │     表示
                     ▼     ▼     ▼
                   保存  共有  削除
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| ArticleCollectionViewController.swift | `Wikipedia/Code/ArticleCollectionViewController.swift` | ソース | 本クラス（基底クラス） |
| ColumnarCollectionViewController.swift | `Wikipedia/Code/ColumnarCollectionViewController.swift` | ソース | 親クラス |
| ArticleRightAlignedImageCollectionViewCell.swift | `Wikipedia/Code/ArticleRightAlignedImageCollectionViewCell.swift` | ソース | 記事表示用セル |
| CollectionViewEditController.swift | `Wikipedia/Code/CollectionViewEditController.swift` | ソース | スワイプ編集コントローラー |
| Action.swift | `Wikipedia/Code/Action.swift` | ソース | アクション定義 |
| ArticleCoordinator.swift | `Wikipedia/Code/ArticleCoordinator.swift` | ソース | 記事画面遷移コーディネーター |
| ArticlePeekPreviewViewController.swift | `Wikipedia/Code/ArticlePeekPreviewViewController.swift` | ソース | 記事プレビュー |
| MWKDataStore.swift | `Wikipedia/Code/MWKDataStore.swift` | ソース | データストア |
| SavedPageList.swift | `Wikipedia/Code/SavedPageList.swift` | ソース | 保存記事リスト |
| ReadingListsFunnel.swift | `Wikipedia/Code/ReadingListsFunnel.swift` | ソース | イベントログ |
