# 画面設計書 14-SavedArticlesCollection画面

## 概要

本ドキュメントは、Wikipedia iOSアプリにおける保存済み記事一覧画面（SavedArticlesCollectionViewController）の設計仕様を定義するものです。

### 本画面の処理概要

保存済み記事一覧画面は、デフォルトリーディングリスト（Saved）に保存されたすべての記事を表示する画面です。ユーザーはこの画面を通じて保存した記事の閲覧、削除、他リストへの追加を行うことができます。また、各記事が所属するリーディングリストのタグも表示されます。

**業務上の目的・背景**：ユーザーがWikipedia記事を素早く保存し、後でアクセスできるようにするための主要なインターフェースです。デフォルトリストは最もアクセス頻度が高いため、専用の画面として提供されています。記事に付与されたリーディングリストのタグにより、どのリストに整理されているかを一目で確認できます。

**画面へのアクセス方法**：タブバーの「Saved」タブをタップし、セグメントコントロールで「All」を選択することでアクセスします。

**主要な操作・処理内容**：
1. デフォルトリストに保存された記事の一覧表示
2. 記事タップで記事詳細画面に遷移
3. 記事の保存解除（unsave）
4. 記事を他のリストに追加
5. リーディングリストタグのタップでリスト詳細に遷移
6. リスト内検索機能
7. ソート機能（タイトル順、追加日順）
8. 初回表示時のログインプロンプト

**画面遷移**：
- 遷移元: Saved画面（SavedViewController）
- 遷移先: Article画面、ReadingListDetail画面、ReadingLists画面（タグタップ時）

**権限による表示制御**：ログインしていないユーザーには、ログインしてリーディングリストを同期するようプロンプトが表示されます。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 14 | 記事保存 | 主機能 | 保存済み記事一覧の表示 |

## 画面種別

一覧

## URL/ルーティング

iOSネイティブアプリのため、URLルーティングは適用されません。NSUserActivityによりSiri/Spotlight検索で"Saved Pages"として表示可能です。

## 入出力項目

| 項目名 | 型 | 入力/出力 | 必須 | 説明 |
|--------|-----|---------|------|------|
| dataStore | MWKDataStore | 入力 | 必須 | データストアへの参照 |

## 表示項目

| 項目名 | 表示形式 | 説明 |
|--------|---------|------|
| 記事タイトル | テキスト | 記事のタイトル（displayTitle） |
| 記事説明 | テキスト | 記事の概要説明 |
| サムネイル画像 | 画像 | 記事のリード画像 |
| リーディングリストタグ | タグボタン群 | 記事が所属する非デフォルトリスト |
| ダウンロード状態 | アイコン | オフライン保存状態 |
| アラートアイコン | アイコン | ダウンロードエラー等の警告 |

## イベント仕様

### 1-記事セル選択

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

- ReadingListEntryCollectionViewControllerのdelegateメソッドを通じて処理
- 記事URLを取得し、親ViewControllerに通知
- 最終的にArticleCoordinatorで記事画面に遷移

### 2-記事の保存解除（Unsave）

記事をデフォルトリストから削除し、すべてのリストから保存を解除。

- スワイプアクションまたはバッチ編集から実行
- ReadingListsAlertControllerで確認ダイアログを表示
- dataStore.readingListsController.unsave()を呼び出し
- アクセシビリティ通知を送信

### 3-記事を他のリストに追加

記事を他のリーディングリストに追加する処理。

- バッチ編集ツールバーの「Add to」ボタンから実行
- AddArticlesToReadingListViewControllerをモーダル表示

### 4-リーディングリストタグ選択

記事に付与されたリーディングリストタグをタップした際の処理。

- タグが最後（...）でない場合: ReadingListDetailViewControllerに遷移
- タグが最後の場合: ReadingListsViewController（フィルタ済み）に遷移

### 5-ログインプロンプト表示

初回表示時にログインを促すパネルを表示。

- viewDidAppear時にwmf_showLoginToSyncSavedArticlesToReadingListPanelOncePerDevice()を呼び出し
- リストが空でない場合のみ表示
- デバイスごとに1回のみ表示

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| 記事保存解除 | SavedArticle | DELETE | 保存状態を解除 |
| 記事保存解除 | ReadingListEntry | UPDATE | すべてのリストからisDeletedLocally=YES |

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

#### SavedArticle / WMFArticle

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| DELETE | savedDate | nil | 保存日をクリア |
| DELETE | isDownloaded | NO | ダウンロード状態をクリア |

## メッセージ仕様

| メッセージID | 種別 | メッセージ内容 | 表示条件 |
|-------------|------|--------------|---------|
| articleDeletedNotification | 通知 | CommonStrings.articleDeletedNotification | 記事削除成功時 |

## 例外処理

| 例外状況 | 処理内容 |
|---------|---------|
| リストが空 | emptyViewType(.noSavedPages)を表示 |
| デフォルトリストが存在しない | initがnilを返す（画面表示不可） |
| ダウンロードエラー | alertButtonCallbackでエラーリカバリを提供 |

## 備考

- ReadingListEntryCollectionViewControllerを継承
- デフォルトリスト専用のサブクラス
- shouldShowEditButtonsForEmptyStateがfalse（空状態でも編集ボタン非表示）
- SavedArticlesCollectionViewCellDelegateでタグ選択を処理
- NSUserActivity.wmf_savedPagesView()でSiri/Spotlightに登録

---

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

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

### 推奨読解順序

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

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

#### Step 2: 基底クラスを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | ReadingListEntryCollectionViewController.swift | `Wikipedia/Code/ReadingListEntryCollectionViewController.swift` | 基底クラスの機能 |

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | SavedArticlesCollectionViewController.swift | `Wikipedia/Code/SavedArticlesCollectionViewController.swift` | デフォルトリスト専用のカスタマイズ |

**主要処理フロー**:
1. **10-17行目**: init - デフォルトリストの取得、emptyViewType設定
2. **23-28行目**: availableBatchEditToolbarActions - unsaveアクション追加
3. **34-40行目**: viewDidAppear - ログインプロンプト表示
4. **42-55行目**: shouldDelete - 確認ダイアログ表示
5. **57-63行目**: delete - unsave処理実行

#### Step 4: タグ選択処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | SavedArticlesCollectionViewController.swift | `Wikipedia/Code/SavedArticlesCollectionViewController.swift` | SavedArticlesCollectionViewCellDelegate拡張（73-82行目） |

**主要処理フロー**:
- **74-81行目**: didSelect(_ tag:) - タグ選択時の遷移処理

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

```
SavedArticlesCollectionViewController
    │  (extends ReadingListEntryCollectionViewController)
    │
    ├─ init()
    │      └─ dataStore.viewContext.defaultReadingList取得
    │
    ├─ viewDidAppear()
    │      └─ wmf_showLoginToSyncSavedArticlesToReadingListPanelOncePerDevice()
    │
    ├─ availableBatchEditToolbarActions
    │      └─ [addToList, unsave]
    │
    ├─ shouldDelete(_:completion:)
    │      └─ ReadingListsAlertController.showAlertIfNeeded()
    │
    ├─ delete(_:)
    │      └─ dataStore.readingListsController.unsave()
    │
    └─ SavedArticlesCollectionViewCellDelegate
           └─ didSelect(_ tag:)
                  ├─ [isLast=false] ReadingListDetailViewController
                  └─ [isLast=true] ReadingListsViewController (filtered)
```

### データフロー図

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

CoreData                  NSFetchedResultsController           UICollectionView
(defaultReadingList)  ───▶ (basePredicate: list == default)  ───▶ SavedArticlesCollectionViewCell
                                                                    └─ タグ表示

ユーザー操作                readingListsController              CoreData更新
(unsave)             ───▶ unsave(articles:in:)              ───▶ (記事保存解除)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| SavedArticlesCollectionViewController.swift | `Wikipedia/Code/SavedArticlesCollectionViewController.swift` | ソース | メインViewController |
| ReadingListEntryCollectionViewController.swift | `Wikipedia/Code/ReadingListEntryCollectionViewController.swift` | ソース | 基底クラス |
| SavedArticlesCollectionViewCell.swift | `Wikipedia/Code/SavedArticlesCollectionViewCell.swift` | ソース | 記事セル（タグ表示対応） |
| ReadingListsController.swift | `Wikipedia/Code/ReadingListsController.swift` | ソース | unsaveロジック |
| ReadingListsAlertController.swift | `Wikipedia/Code/ReadingListsAlertController.swift` | ソース | 確認ダイアログ |
| AddArticlesToReadingListViewController.swift | `Wikipedia/Code/AddArticlesToReadingListViewController.swift` | ソース | リスト追加画面 |
