# 画面設計書 12-ReadingListDetail画面

## 概要

本ドキュメントは、Wikipedia iOSアプリにおけるリーディングリスト詳細画面（ReadingListDetailViewController）の設計仕様を定義するものです。

### 本画面の処理概要

リーディングリスト詳細画面は、特定のリーディングリストに保存された記事の一覧を表示し、リストの編集・管理を行うための画面です。ユーザーはこの画面を通じてリスト内の記事の閲覧、削除、他リストへの移動、およびリスト自体の名前・説明の編集を行うことができます。

**業務上の目的・背景**：リーディングリストは複数の記事を整理するためのコンテナです。ユーザーはリスト詳細画面で保存した記事にアクセスし、オフラインで読むことができます。また、リストの名前や説明を編集してより整理しやすくしたり、不要な記事を削除したりする必要があります。本画面はこれらの操作を提供する中心的なインターフェースです。

**画面へのアクセス方法**：ReadingLists画面（リーディングリスト一覧）でリストをタップすることでアクセスします。また、共有リーディングリストのインポート時にモーダルとして表示されることもあります。

**主要な操作・処理内容**：
1. リスト内の保存記事一覧を表示（タイトル、説明、サムネイル画像）
2. 記事タップで記事詳細画面に遷移
3. リストの名前・説明を編集（ヘッダー部分）
4. 記事の削除（スワイプアクションまたはバッチ編集モード）
5. 記事を他のリストに追加または移動
6. リスト内検索機能
7. ソート機能（タイトル順、追加日順）
8. 共有リーディングリストインポート時のサーベイ表示

**画面遷移**：
- 遷移元: ReadingLists画面、共有リンクからのインポート
- 遷移先: Article画面、AddArticlesToReadingList画面

**権限による表示制御**：デフォルトリスト（Saved）の場合、名前・説明の編集は不可。記事の削除・移動は可能。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 15 | リーディングリスト管理 | 主機能 | リーディングリストの詳細と記事一覧表示 |

## 画面種別

詳細 / 一覧（複合）

## URL/ルーティング

iOSネイティブアプリのため、URLルーティングは適用されません。ViewControllerのプッシュ遷移またはモーダル表示により画面を表示します。

## 入出力項目

| 項目名 | 型 | 入力/出力 | 必須 | 説明 |
|--------|-----|---------|------|------|
| readingList | ReadingList | 入力 | 必須 | 表示するリーディングリスト |
| dataStore | MWKDataStore | 入力 | 必須 | データストアへの参照 |
| displayType | ReadingListDetailDisplayType | 入力 | 任意 | .pushed（デフォルト）または .modal |
| fromImport | Bool | 入力 | 任意 | 共有リンクからのインポートかどうか |
| theme | Theme | 入力 | 必須 | 表示テーマ |

## 表示項目

| 項目名 | 表示形式 | 説明 |
|--------|---------|------|
| リスト名 | テキスト（編集可能） | リーディングリストの名前 |
| リスト説明 | テキスト（編集可能） | リーディングリストの説明文 |
| 記事数 | テキスト | リスト内の記事数 |
| アラート表示 | バナー | リスト制限超過時の警告 |
| 記事タイトル | テキスト | 各記事のタイトル |
| 記事サムネイル | 画像 | 各記事のリード画像 |
| 記事説明 | テキスト | 各記事の説明文 |
| ダウンロード状態 | アイコン | オフライン保存状態 |

## イベント仕様

### 1-記事セル選択

記事セルをタップした際の処理。

- ArticleCoordinatorを生成し、記事画面に遷移
- モーダル表示の場合は、presentingViewControllerのナビゲーションスタックを利用
- プッシュ表示の場合は、現在のnavigationControllerを利用

### 2-ヘッダー編集

リスト名・説明を編集する処理。

- ReadingListDetailHeaderViewのテキストフィールドを編集モードに
- 完了時、dataStore.readingListsController.updateReadingList()を呼び出し
- タイトルが空の場合、保存ボタンを無効化

### 3-記事削除

記事を削除する処理。

- スワイプアクションまたはバッチ編集から実行
- dataStore.readingListsController.remove(articles:readingList:)を呼び出し
- アクセシビリティ通知を送信

### 4-記事の追加/移動

記事を他のリストに追加または移動する処理。

- AddArticlesToReadingListViewControllerをモーダル表示
- moveFromReadingListを指定すると移動モード

### 5-検索

リスト内の記事を検索する処理。

- ナビゲーションバーのSearchControllerを使用
- UISearchResultsUpdatingで検索文字列を取得
- ReadingListEntryCollectionViewControllerのupdateSearchString()を呼び出し

### 6-ソート

記事のソート順を変更する処理。

- sortBarButtonItemタップでアラートシートを表示
- タイトル順または追加日順を選択

### 7-共有リストサーベイ表示

インポートされた共有リストのサーベイを表示（条件付き）。

- fromImport=trueの場合、5秒後にサーベイプロンプトを表示
- ユーザーがサーベイを完了済みの場合は表示しない
- 言語に応じたサーベイURLを選択

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| リスト名編集 | ReadingList | UPDATE | canonicalName、readingListDescriptionを更新 |
| 記事削除 | ReadingListEntry | UPDATE | isDeletedLocallyをYESに設定 |
| 記事移動 | ReadingListEntry | DELETE/INSERT | 元リストから削除、新リストに追加 |

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

#### ReadingList

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | canonicalName | ヘッダーの入力値 | リスト名 |
| UPDATE | readingListDescription | ヘッダーの入力値 | 説明（任意） |

#### ReadingListEntry

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE(削除) | isDeletedLocally | YES | 論理削除フラグ |
| INSERT(移動) | list | 移動先ReadingList | 新規エントリ作成 |

## メッセージ仕様

| メッセージID | 種別 | メッセージ内容 | 表示条件 |
|-------------|------|--------------|---------|
| reading-list-detail-search-placeholder | プレースホルダー | "Search reading list" | 検索バー |
| articleDeletedNotification | 通知 | CommonStrings.articleDeletedNotification | 記事削除成功時 |

## 例外処理

| 例外状況 | 処理内容 |
|---------|---------|
| リストが空 | emptyViewType(.noSavedPagesInReadingList)を表示 |
| 記事取得エラー | alertButtonCallbackでエラーリカバリを提供 |
| ネットワークエラー | ローカルキャッシュから表示継続 |

## 備考

- ReadingListEntryCollectionViewControllerを子ViewControllerとして使用
- ReadingListDetailHeaderViewでリスト情報のヘッダーを表示
- デフォルトリストの場合、shouldShowEditButtonsForEmptyStateがfalseになる
- CollectionViewEditControllerNavigationDelegateで編集状態のナビゲーションを管理

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | ReadingList+CoreDataClass.swift | `Wikipedia/Code/ReadingList+CoreDataClass.swift` | ReadingListエンティティ、isDefaultフラグ |
| 1-2 | ReadingListEntry+CoreDataClass.swift | `Wikipedia/Code/ReadingListEntry+CoreDataClass.swift` | リストと記事の関連 |

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | ReadingListDetailViewController.swift | `Wikipedia/Code/ReadingListDetailViewController.swift` | メインコンテナViewController |

**主要処理フロー**:
1. **37-53行目**: init - 初期化、ReadingListEntryCollectionViewControllerの生成
2. **102-107行目**: viewDidLoad - 子ViewControllerのセットアップ
3. **134-143行目**: configureNavigationBar - ナビゲーションバー設定

#### Step 3: 子ViewControllerを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | ReadingListEntryCollectionViewController.swift | `Wikipedia/Code/ReadingListEntryCollectionViewController.swift` | 記事一覧の表示・編集ロジック |

**主要処理フロー**:
- **54-62行目**: init - FetchedResultsControllerの対象リスト設定
- **98-114行目**: configure(cell:for:at:layoutOnly:) - セルの設定
- **478-491行目**: collectionView(_:didSelectItemAt:) - 記事選択時の処理

#### Step 4: ヘッダービューを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | ReadingListDetailHeaderView.swift | `Wikipedia/Code/ReadingListDetailHeaderView.swift` | リスト情報表示・編集ヘッダー |

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

```
ReadingListDetailViewController
    │
    ├─ viewDidLoad()
    │      └─ setUpArticlesViewController()
    │             └─ ReadingListEntryCollectionViewController (子VC追加)
    │
    ├─ configureNavigationBar()
    │      └─ WMFNavigationBarConfiguring設定
    │
    ├─ ReadingListEntryCollectionViewControllerDelegate
    │      ├─ setupReadingListDetailHeaderView()
    │      ├─ readingListEntryCollectionViewController(_:didUpdate:)
    │      ├─ readingListEntryCollectionViewControllerDidChangeEmptyState()
    │      └─ readingListEntryCollectionViewControllerDidSelectArticleURL()
    │             └─ ArticleCoordinator.start()
    │
    └─ CollectionViewEditControllerNavigationDelegate
           └─ didChangeEditingState()
                  └─ ReadingListDetailHeaderView.beginEditing()/finishEditing()
```

### データフロー図

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

ReadingList             ReadingListEntryCollectionViewController   UICollectionView
(対象リスト)        ───▶ NSFetchedResultsController              ───▶ (SavedArticlesCollectionViewCell)
                         (basePredicate: list == readingList)

ユーザー編集             ReadingListDetailHeaderView               CoreData更新
(名前/説明)         ───▶ finishEditing()                        ───▶ (ReadingList更新)
                         └─ readingListsController.updateReadingList()
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| ReadingListDetailViewController.swift | `Wikipedia/Code/ReadingListDetailViewController.swift` | ソース | メインコンテナViewController |
| ReadingListEntryCollectionViewController.swift | `Wikipedia/Code/ReadingListEntryCollectionViewController.swift` | ソース | 記事一覧の表示・編集 |
| ReadingListDetailHeaderView.swift | `Wikipedia/Code/ReadingListDetailHeaderView.swift` | ソース | ヘッダービュー |
| ReadingListDetailHeaderView.xib | `Wikipedia/Code/ReadingListDetailHeaderView.xib` | XIB | ヘッダービューのレイアウト |
| SavedArticlesCollectionViewCell.swift | `Wikipedia/Code/SavedArticlesCollectionViewCell.swift` | ソース | 記事表示用セル |
| ArticleCoordinator.swift | `Wikipedia/Code/ArticleCoordinator.swift` | ソース | 記事画面遷移 |
| CollectionViewEditController.swift | `Wikipedia/Code/CollectionViewEditController.swift` | ソース | 編集機能の共通ロジック |
