# 画面設計書 11-ReadingLists画面

## 概要

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

### 本画面の処理概要

リーディングリスト一覧画面は、ユーザーが保存したリーディングリストを一覧表示し、管理するための画面です。ユーザーはこの画面を通じてリストの閲覧、作成、削除、および記事のリストへの追加を行うことができます。

**業務上の目的・背景**：Wikipedia記事を後で読むために保存する機能は、モバイルアプリの主要なユースケースの一つです。複数のリーディングリストを作成することで、ユーザーは関心のあるトピックごとに記事を整理でき、オフラインでの閲覧も可能になります。本画面は、これらのリストを効率的に管理するための中心的なインターフェースを提供します。

**画面へのアクセス方法**：タブバーの「Saved」タブをタップし、セグメントコントロールで「Reading lists」を選択することでアクセスできます。また、記事を保存する際の「Add to reading list」アクションシートからもアクセス可能です。

**主要な操作・処理内容**：
1. リーディングリスト一覧の表示（タイトル、説明、記事数、プレビュー画像を含む）
2. 新しいリーディングリストの作成（「+」ボタンまたは空状態画面から）
3. 既存リストの削除（スワイプアクションまたはバッチ編集モード）
4. リストの詳細画面への遷移（リストタップ）
5. 記事を特定のリストに追加（addArticlesToReadingListモードの場合）
6. リストの検索とソート（タイトル順、追加日順）
7. Pull-to-refreshによるデータ同期

**画面遷移**：
- 遷移元: Saved画面（SavedViewController）、記事追加アクションシート
- 遷移先: ReadingListDetail画面、CreateReadingList画面

**権限による表示制御**：デフォルトリーディングリスト（Saved）は常に表示され、編集・削除不可。ログインユーザーはリーディングリストの同期機能が有効になります。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 15 | リーディングリスト管理 | 主機能 | リーディングリスト一覧表示と管理 |
| 17 | リスト新規作成 | 補助機能 | 新しいリーディングリストの作成ボタン |

## 画面種別

一覧

## URL/ルーティング

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

## 入出力項目

| 項目名 | 型 | 入力/出力 | 必須 | 説明 |
|--------|-----|---------|------|------|
| dataStore | MWKDataStore | 入力 | 必須 | データストアへの参照 |
| articles | [WMFArticle] | 入力 | 任意 | リストに追加する記事（addArticlesToReadingListモード時） |
| readingLists | [ReadingList] | 入力 | 任意 | 表示するリストを限定する場合 |
| displayType | ReadingListsDisplayType | 入力 | 必須 | .readingListsTab または .addArticlesToReadingList |
| delegate | ReadingListsViewControllerDelegate | 入力 | 任意 | デリゲート |

## 表示項目

| 項目名 | 表示形式 | 説明 |
|--------|---------|------|
| リスト名 | テキスト | リーディングリストの名前（canonicalName） |
| リスト説明 | テキスト | リーディングリストの説明文 |
| 記事数 | テキスト | リスト内の記事数（countOfEntries） |
| プレビュー画像 | サムネイル画像 | 最大4件の記事のリード画像 |
| アラートアイコン | アイコン | リスト制限超過等の警告表示 |
| 新規作成ボタン | ボタン | ヘッダー内の「Create new list」ボタン（addArticlesToReadingListモード時） |

## イベント仕様

### 1-リストセル選択

リーディングリストのセルをタップした際の処理。

**readingListsTabモードの場合**:
- ReadingListDetailViewControllerを生成し、プッシュ遷移
- 選択したリストと現在のthemeを引き継ぎ

**addArticlesToReadingListモードの場合**:
- readingListsController.add(articles:to:)を呼び出し、記事をリストに追加
- delegateのdidAddArticles(_:to:)を呼び出し

### 2-新規作成ボタンタップ

新しいリーディングリストを作成するモーダルを表示。

- CreateReadingListViewControllerを生成
- WMFComponentNavigationControllerでラップしてモーダル表示
- 記事がある場合は、作成後に自動追加

### 3-スワイプ削除

リストセルを左スワイプして削除アクションを表示。

- ReadingListsAlertControllerで確認ダイアログを表示
- 確認後、readingListsController.delete(readingLists:)を実行
- アクセシビリティ通知を送信

### 4-バッチ編集削除

複数のリストを一括削除。

- collectionView.indexPathsForSelectedItemsから選択されたリストを取得
- ReadingListsAlertControllerで確認ダイアログを表示
- 確認後、一括削除を実行

### 5-ソートアラート表示

ソートボタンタップでアラートシートを表示。

- タイトル順（byTitle）または追加日順（byRecentlyAdded）を選択
- 選択後、reset()を呼び出してリストを再取得

### 6-プルリフレッシュ

下に引っ張ってデータを同期。

- dataStore.readingListsController.fullSync()を実行
- 完了後、endRefreshing()を呼び出し

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| リスト作成 | ReadingList | INSERT | 新しいリーディングリストエンティティを作成 |
| リスト削除 | ReadingList | UPDATE | isDeletedLocallyをYESに設定（論理削除） |
| 記事追加 | ReadingListEntry | INSERT | リストと記事の関連エントリを作成 |
| ソート順変更 | - | - | メモリ上のソート（CoreDataクエリの変更） |

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

#### ReadingList

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | canonicalName | ユーザー入力値 | リスト名 |
| INSERT | readingListDescription | ユーザー入力値 | 説明（任意） |
| INSERT | createdDate | 現在日時 | 作成日時 |
| INSERT | isDefault | NO | デフォルトリストはシステム作成 |
| UPDATE(削除) | isDeletedLocally | YES | 論理削除フラグ |

#### ReadingListEntry

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | list | 対象ReadingList | リストへの参照 |
| INSERT | articleKey | 記事のキー | 記事の識別子 |
| INSERT | createdDate | 現在日時 | 追加日時 |

## メッセージ仕様

| メッセージID | 種別 | メッセージ内容 | 表示条件 |
|-------------|------|--------------|---------|
| reading-list-deleted-accessibility-notification | 通知 | "Reading list deleted" | リスト削除成功時（アクセシビリティ） |
| unknown-error | エラー | CommonStrings.unknownError | 予期しないエラー発生時 |
| 各ReadingListError | エラー | localizedDescription | リーディングリスト操作エラー時 |

## 例外処理

| 例外状況 | 処理内容 |
|---------|---------|
| リストが空 | emptyViewType(.noReadingLists)を表示し、新規作成ボタンを提供 |
| リスト作成エラー | WMFAlertManagerでエラーメッセージをスティッキー表示 |
| 同名リスト存在 | CreateReadingListViewControllerのhandleReadingListNameErrorを呼び出し |
| ネットワークエラー | 同期失敗時はローカルデータを表示継続 |

## 備考

- デフォルトリスト（Saved）はisDefault=YESで識別され、削除・編集不可
- isDefaultListEnabledフラグでデフォルトリストの表示/非表示を制御
- NSFetchedResultsControllerを使用してCoreDataの変更を自動反映
- CollectionViewUpdaterでコレクションビューの更新を管理

---

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

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

### 推奨読解順序

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

まず、プログラム間で受け渡されるデータ構造を理解することが重要。

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

**読解のコツ**: CoreData生成ファイルのため、プロパティ定義とリレーションシップに注目。

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

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

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

**主要処理フロー**:
1. **147-156行目**: viewDidLoad - セルの登録、編集コントローラのセットアップ
2. **164-178行目**: viewWillAppear/viewDidDisappear - FetchedResultsControllerのライフサイクル管理
3. **68-105行目**: setupFetchedResultsController - データ取得の設定

#### Step 3: データ取得層を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | ReadingListsViewController.swift | `Wikipedia/Code/ReadingListsViewController.swift` | setupFetchedResultsController()メソッド（68-105行目） |
| 3-2 | ReadingListsController.swift | `Wikipedia/Code/ReadingListsController.swift` | リーディングリストのCRUD操作 |

**主要処理フロー**:
- **68-105行目**: NSFetchRequestの組み立て、predicateの設定
- **102-104行目**: sortDescriptorsの適用、FetchedResultsControllerの生成

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | ReadingListsCollectionViewCell.swift | `Wikipedia/Code/ReadingListsCollectionViewCell.swift` | セルの表示ロジック |
| 4-2 | ReadingListsViewController.swift | `Wikipedia/Code/ReadingListsViewController.swift` | configure(cell:forItemAt:layoutOnly:)メソッド（222-243行目） |

**主要処理フロー**:
- **222-243行目**: セルの設定、デフォルトリストと通常リストの表示分岐

#### Step 5: 編集機能を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | ReadingListsViewController+ActionDelegate.swift | `Wikipedia/Code/ReadingListsViewController.swift` | ActionDelegate拡張（436-524行目） |
| 5-2 | CollectionViewEditController.swift | `Wikipedia/Code/CollectionViewEditController.swift` | スワイプ・バッチ編集の共通ロジック |

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

```
ReadingListsViewController
    │
    ├─ viewDidLoad()
    │      ├─ layoutManager.register() - セル登録
    │      └─ setupEditController() - 編集機能セットアップ
    │
    ├─ viewWillAppear()
    │      ├─ setupFetchedResultsController()
    │      │      └─ NSFetchedResultsController生成
    │      ├─ setupCollectionViewUpdater()
    │      └─ fetch()
    │
    ├─ collectionView(_:cellForItemAt:)
    │      └─ configure(cell:forItemAt:layoutOnly:)
    │             └─ ReadingListsCollectionViewCell.configure()
    │
    ├─ collectionView(_:didSelectItemAt:)
    │      ├─ [readingListsTab] ReadingListDetailViewController生成
    │      └─ [addArticlesToReadingList] readingListsController.add()
    │
    └─ didPerformAction(_:) / didPerformBatchEditToolbarAction(_:)
           └─ readingListsController.delete()
```

### データフロー図

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

CoreData             NSFetchedResultsController      UICollectionView
(ReadingList)   ───▶ (basePredicate +           ───▶ (ReadingListsCollectionViewCell)
                      sortDescriptors)

ユーザー操作         ReadingListsController           CoreData更新
(追加/削除)     ───▶ (create/delete)             ───▶ (ReadingList/ReadingListEntry)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| ReadingListsViewController.swift | `Wikipedia/Code/ReadingListsViewController.swift` | ソース | メインViewController |
| ReadingListsCollectionViewCell.swift | `Wikipedia/Code/ReadingListsCollectionViewCell.swift` | ソース | リスト表示用セル |
| ReadingListsController.swift | `Wikipedia/Code/ReadingListsController.swift` | ソース | リストのCRUD操作 |
| CollectionViewEditController.swift | `Wikipedia/Code/CollectionViewEditController.swift` | ソース | 編集機能の共通ロジック |
| ColumnarCollectionViewController.swift | `Wikipedia/Code/ColumnarCollectionViewController.swift` | ソース | 基底クラス |
| ReadingList+CoreDataClass.swift | `Wikipedia/Code/ReadingList+CoreDataClass.swift` | ソース | CoreDataエンティティ |
| ReadingListEntry+CoreDataClass.swift | `Wikipedia/Code/ReadingListEntry+CoreDataClass.swift` | ソース | CoreDataエンティティ |
| CreateNewReadingListButtonView.xib | `Wikipedia/Code/CreateNewReadingListButtonView.xib` | XIB | 新規作成ボタンビュー |
