# 画面設計書 81-ArticleURLList画面

## 概要

本ドキュメントは、Wikipedia iOSアプリにおけるArticleURLList画面の設計仕様を定義するものである。この画面は、URLリストで指定された記事の一覧を表示するためのコンポーネントである。

### 本画面の処理概要

ArticleURLList画面は、外部から渡されたURL配列に基づいて記事の一覧をコレクションビュー形式で表示する画面である。主にExploreフィードの「もっと見る」やコンテンツグループからの詳細一覧表示に使用される。

**業務上の目的・背景**：Exploreフィードでは、各コンテンツカード（ニュース、おすすめ記事など）に関連する記事が複数存在する場合があり、それらを一覧形式で閲覧するニーズがある。本画面は、そのような記事群をまとめて表示し、ユーザーが興味のある記事を選択して詳細を閲覧できるようにする。フィードのスペースを有効活用しながら、関連コンテンツへのアクセシビリティを向上させる役割を担う。

**画面へのアクセス方法**：Explore画面のフィードカード（コンテンツグループ）から「もっと見る」「すべて見る」などのアクションをタップすることでプッシュ遷移により表示される。

**主要な操作・処理内容**：
1. 指定されたURLリストに基づく記事一覧の表示
2. 各記事アイテムのタップによる記事詳細画面（Article画面）への遷移
3. スワイプアクション（保存、共有など）による記事操作
4. コンテキストメニュー（ロングプレス）による記事プレビュー表示
5. ナビゲーションバーの「戻る」ボタンで前画面への復帰

**画面遷移**：
- 遷移元：Explore画面（コンテンツグループのフィードカード）
- 遷移先：Article画面（記事詳細）、ArticlePeekPreview画面（プレビュー）

**権限による表示制御**：特になし。ただし、記事保存アクション（リーディングリストへの追加）はログイン状態によって同期の有無が異なる。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 1 | 記事表示 | 主機能 | URL指定記事リスト表示 |
| 7 | 探索フィード | 遷移元機能 | フィードカードからの遷移 |
| 14 | 記事保存 | 補助機能 | 記事をリーディングリストに保存 |
| 5 | 記事共有 | 補助機能 | 記事URLの共有 |

## 画面種別

一覧

## URL/ルーティング

iOSネイティブアプリのため、URLルーティングなし。`ArticleURLListViewController`クラスの初期化時に`articleURLs`配列を渡すことで画面が構成される。

## 入出力項目

| 項目名 | 型 | 入力/出力 | 必須 | 説明 |
|--------|------|---------|------|------|
| articleURLs | [URL] | 入力 | 必須 | 表示する記事のURLリスト |
| dataStore | MWKDataStore | 入力 | 必須 | データストアへの参照 |
| contentGroup | WMFContentGroup | 入力 | 任意 | 関連するコンテンツグループ（イベントログ用） |
| theme | Theme | 入力 | 必須 | 現在のテーマ設定 |

## 表示項目

| 項目名 | 説明 | 表示形式 |
|--------|------|----------|
| 記事タイトル | 記事の表示タイトル | テキスト |
| 記事説明 | 記事の概要説明 | テキスト（1行） |
| 記事サムネイル | 記事のサムネイル画像 | 画像（右寄せ） |
| セパレーター | セル間の区切り線 | 水平線 |

## イベント仕様

### 1-記事セル選択

ユーザーがコレクションビューの記事セルをタップした際の処理。

1. `collectionView(_:didSelectItemAt:)`が呼び出される
2. `articleURL(at:)`で選択されたインデックスパスに対応するURLを取得
3. `ArticleCoordinator`を初期化し、記事詳細画面への遷移を開始
4. 記事詳細画面がナビゲーションスタックにプッシュされる

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

セルを左にスワイプした際に表示されるアクションメニュー。

1. 保存/未保存アクション：記事のリーディングリスト保存状態を切り替え
2. 共有アクション：記事URLを他アプリと共有
3. 削除アクション（サブクラス実装時）：記事をリストから削除

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

セルをロングプレスした際のプレビュー表示。

1. `previewingViewController(for:at:)`が呼び出される
2. `ArticlePeekPreviewViewController`が生成され、プレビューが表示される
3. プレビューから記事詳細画面への遷移が可能

### 4-フッターボタン押下

コレクションビューフッターのボタン押下時の処理。

1. `collectionViewFooterButtonWasPressed(_:)`が呼び出される
2. `navigationController?.popViewController(animated:)`で前画面に戻る

### 5-記事更新通知受信

バックグラウンドで記事データが更新された際の処理。

1. `WMFArticleUpdated`通知を受信
2. `articleDidChange(_:)`で更新された記事がこのリストに含まれるか確認
3. 含まれる場合、`collectionView.reloadData()`で表示を更新

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| 記事保存 | ReadingListEntry | INSERT | リーディングリストに記事を追加 |
| 記事保存解除 | ReadingListEntry | DELETE | リーディングリストから記事を削除 |
| 画面表示 | WMFArticle | SELECT | URLに基づいて記事データを取得または作成 |

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

#### WMFArticle

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT/INSERT | key | URLのデータベースキー | fetchOrCreateArticle使用 |

## メッセージ仕様

| メッセージID | 種別 | メッセージ内容 | 表示条件 |
|-------------|------|--------------|----------|
| - | 通知 | 記事を保存しました | 記事保存成功時（VoiceOver） |
| - | 通知 | 記事の保存を解除しました | 記事保存解除時（VoiceOver） |

## 例外処理

| 例外条件 | 処理内容 |
|---------|---------|
| 記事URLが無効 | 該当アイテムをスキップ（クラッシュ防止） |
| データストア未設定 | DEBUG時にアサーション失敗、本番では処理継続 |
| 記事取得失敗 | nilを返却し、セル設定をスキップ |

## 備考

- ArticleCollectionViewControllerを継承しており、記事一覧表示の共通機能を活用
- イベントログ用にcontentGroupを保持し、フィードカテゴリとラベルを記録
- hidesBottomBarWhenPushedがtrueに設定されており、タブバーは非表示になる

---

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

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

### 推奨読解順序

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

まず、画面で扱うデータモデルとその関係を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | WMFArticle | `WMF/Sources/WMF/DataStore/WMFArticle+*.swift` | 記事データモデル、URLからのキー生成ロジック |
| 1-2 | WMFContentGroup | `WMF/Sources/WMF/DataStore/WMFContentGroup*.swift` | コンテンツグループの構造（イベントログ用） |

**読解のコツ**: WMFArticleはCoreDataエンティティであり、`key`プロパティがURLのデータベースキーとして使用される。

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

処理の起点となるViewControllerの初期化と基本構造。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | ArticleURLListViewController.swift | `Wikipedia/Code/ArticleURLListViewController.swift` | 初期化処理、プロパティの設定 |

**主要処理フロー**:
1. **9-18行目**: `init(articleURLs:dataStore:contentGroup:theme:)` - 初期化でURLリストとデータストアを設定
2. **11行目**: `articleKeys`セットの生成 - URL→databaseKey変換
3. **54-58行目**: `viewDidLoad()` - コレクションビューのリロードと通知オブザーバー登録

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

ArticleCollectionViewControllerの共通機能を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | ArticleCollectionViewController.swift | `Wikipedia/Code/ArticleCollectionViewController.swift` | 記事コレクションの基底クラス |
| 3-2 | ColumnarCollectionViewController.swift | `Wikipedia/Code/ColumnarCollectionViewController.swift` | カラムレイアウトの基底クラス |

**主要処理フロー**:
- **15-24行目**: `viewDidLoad()` - セル登録、編集コントローラーセットアップ
- **26-35行目**: `configure(cell:forItemAt:layoutOnly:)` - セルの設定
- **174-183行目**: `collectionView(_:didSelectItemAt:)` - 記事詳細への遷移

#### Step 4: データソース実装を理解する

コレクションビューへのデータ供給方法を把握する。

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

**主要処理フロー**:
- **40-45行目**: `articleURL(at:)` - インデックスパスからURLを取得
- **47-52行目**: `article(at:)` - URLから記事オブジェクトを取得
- **97-103行目**: `numberOfSections`, `numberOfItemsInSection` - セクション数とアイテム数

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

```
ArticleURLListViewController
    │
    ├─ init(articleURLs:dataStore:contentGroup:theme:)
    │      └─ articleKeys生成（URL→databaseKey）
    │
    ├─ viewDidLoad()
    │      ├─ super.viewDidLoad() → ArticleCollectionViewController
    │      │      ├─ layoutManager.register() - セル登録
    │      │      └─ setupEditController() - 編集機能設定
    │      ├─ collectionView.reloadData()
    │      └─ NotificationCenter.addObserver() - 記事更新通知
    │
    ├─ articleURL(at:) → URL取得
    │
    ├─ article(at:) → dataStore.fetchOrCreateArticle()
    │
    └─ collectionView(_:didSelectItemAt:)
           └─ ArticleCoordinator.start() → Article画面遷移
```

### データフロー図

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

articleURLs ──────▶ ArticleURLListViewController ──────▶ UICollectionView
(URL配列)                      │                          (記事一覧表示)
                               │
dataStore ─────────▶ fetchOrCreateArticle() ───────────▶ WMFArticle
                               │
                               ▼
                    セルタップ → ArticleCoordinator ────▶ Article画面
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| ArticleURLListViewController.swift | `Wikipedia/Code/ArticleURLListViewController.swift` | ソース | メインViewController |
| ArticleCollectionViewController.swift | `Wikipedia/Code/ArticleCollectionViewController.swift` | ソース | 記事コレクション基底クラス |
| ColumnarCollectionViewController.swift | `Wikipedia/Code/ColumnarCollectionViewController.swift` | ソース | カラムレイアウト基底クラス |
| ArticleRightAlignedImageCollectionViewCell.swift | `Wikipedia/Code/ArticleRightAlignedImageCollectionViewCell.swift` | ソース | 記事セルUI |
| ArticleCoordinator.swift | `Wikipedia/Code/ArticleCoordinator.swift` | ソース | 記事画面遷移コーディネーター |
| MWKDataStore.swift | `WMF/Sources/WMF/DataStore/MWKDataStore.swift` | ソース | データストア |
| WMFArticle | `WMF/Sources/WMF/DataStore/` | ソース | 記事データモデル |
