# 画面設計書 30-PageHistory画面

## 概要

本ドキュメントは、Wikipedia iOSアプリにおけるページ履歴画面（PageHistoryViewController）の設計仕様を記載したものである。

### 本画面の処理概要

PageHistory画面は、Wikipedia記事の編集履歴（リビジョン）一覧を表示する画面である。各リビジョンの編集者、日時、変更サイズ、コメントを表示し、2つのリビジョンを選択して差分を比較する機能を提供する。また、記事の編集統計（総編集回数、編集者タイプ別内訳、編集頻度のグラフ）をヘッダーに表示する。

**業務上の目的・背景**：Wikipediaは多くの編集者による共同編集で成り立っており、記事の履歴を確認することは品質管理や編集の追跡に不可欠である。本画面は、記事がどのように変遷してきたかを視覚的に理解し、特定のリビジョン間の差分を比較できるようにすることで、編集の透明性と品質向上に貢献する。

**画面へのアクセス方法**：Article画面のメニューから「History」を選択

**主要な操作・処理内容**：
1. リビジョン一覧をスクロールして閲覧（ページネーション対応）
2. 特定のリビジョンをタップして単一リビジョンの差分を表示
3. 「Compare」ボタンで比較モードに入り、2つのリビジョンを選択
4. 選択した2つのリビジョン間の差分を比較
5. ヘッダーで編集統計を確認

**画面遷移**：
- 遷移元：Article画面
- 遷移先：DiffContainer画面（差分比較）

**権限による表示制御**：特になし。全ユーザーが閲覧可能。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 24 | 編集履歴 | 主機能 | 記事の編集履歴一覧表示 |
| 25 | 差分比較 | 遷移先機能 | リビジョン選択で差分比較画面へ遷移 |

## 画面種別

一覧画面（無限スクロール対応）

## URL/ルーティング

iOSネイティブアプリのため、URLベースのルーティングは存在しない。

## 入出力項目

### 入力項目

| 項目名 | 種別 | データ型 | 必須 | 説明 |
|--------|------|----------|------|------|
| pageTitle | 入力 | String | 必須 | 記事タイトル |
| pageURL | 入力 | URL | 必須 | 記事のURL |
| articleSummaryController | 入力 | ArticleSummaryController | 必須 | 記事サマリー取得用 |
| authenticationManager | 入力 | WMFAuthenticationManager | 必須 | 認証管理 |

### 出力項目

なし（画面表示のみ）

## 表示項目

### ナビゲーションバー

| 項目名 | 表示内容 | 備考 |
|--------|----------|------|
| タイトル | "History" | CommonStrings.historyTabTitle |
| 右ボタン（通常） | "Compare" | 比較モード開始 |
| 右ボタン（比較中） | "Cancel" | 比較モードキャンセル |

### ヘッダー（PageHistoryCountsView）

| 項目名 | 表示内容 | 備考 |
|--------|----------|------|
| 記事タイトル | pageTitle | - |
| 総編集回数 | 編集回数 | totalEditCount |
| 初回編集日 | 日付 | firstEditDate |
| 編集者タイプ別内訳 | 円グラフ/リスト | editCountsGroupedByType |
| 編集頻度 | 時系列グラフ | timeseriesOfEditsCounts |

### リビジョン一覧

| 項目名 | 表示内容 | 備考 |
|--------|----------|------|
| 時刻 | 編集時刻 | 今日の場合は相対表示 |
| 編集者 | ユーザー名 | - |
| 編集者アイコン | user-edit/anon/temp | 登録/匿名/一時ユーザー |
| サイズ差分 | +/-バイト数 | 色分け表示 |
| コメント | 編集サマリー | HTML除去済み |
| マイナー編集 | 小さい編集マーク | isMinor |

### 比較選択UI（PageHistoryComparisonSelectionViewController）

| 項目名 | 表示内容 | 備考 |
|--------|----------|------|
| 選択ボタン1 | 最初の選択リビジョン | 青系テーマ |
| 選択ボタン2 | 2番目の選択リビジョン | オレンジ系テーマ |
| 比較ボタン | "Compare" | 2つ選択時に有効化 |

## イベント仕様

### 1-リビジョン一覧のスクロール

リビジョン一覧をスクロールして閲覧。画面下部に近づくと追加データを取得。

**処理フロー**：
1. scrollViewDidScrollが呼び出される
2. shouldLoadNewDataを確認（batchComplete, isLoadingData, maxY条件）
3. 条件を満たす場合、getPageHistory()を呼び出し
4. pageHistoryFetcher.fetchRevisionInfoで追加データを取得
5. appendSections(from:)で既存データに追加
6. collectionView.reloadData()で表示更新

### 2-リビジョンタップ（通常モード）

特定のリビジョンをタップして、そのリビジョンと前のリビジョンの差分を表示。

**処理フロー**：
1. collectionView(_:didSelectItemAt:)が呼び出される
2. state == .idleの場合、pushToSingleRevisionDiff(indexPath:)を実行
3. 選択リビジョンとその前のリビジョンを取得
4. showDiff(from:to:type:)でDiffContainerViewControllerを生成・遷移

### 3-Compareボタンタップ

比較モードを開始する。

**処理フロー**：
1. compare(_:)メソッドが呼び出される
2. EditHistoryCompareFunnel.shared.logCompare1(articleURL:)でロギング
3. state = .editingに変更
4. UIが比較モードに切り替わり、選択UIが表示される

### 4-リビジョン選択（比較モード）

2つのリビジョンを選択する。

**処理フロー**：
1. collectionView(_:didSelectItemAt:)が呼び出される
2. state == .editingの場合、選択処理を実行
3. selectedCellsCountをインクリメント
4. 選択テーマモデルを適用（firstSelectionThemeModel/secondSelectionThemeModel）
5. comparisonSelectionViewControllerのボタンを更新
6. 2つ選択時、compareButtonを有効化

### 5-比較ボタンタップ（2リビジョン選択後）

選択した2つのリビジョン間の差分を表示。

**処理フロー**：
1. pageHistoryComparisonSelectionViewControllerDidTapCompareが呼び出される
2. EditHistoryCompareFunnel.shared.logCompare2(articleURL:)でロギング
3. 2つのリビジョンを日付順にソート（古い方がfrom）
4. showDiff(from:to:type: .compare)でDiffContainerViewControllerを生成・遷移

### 6-キャンセルボタンタップ

比較モードをキャンセル。

**処理フロー**：
1. cancelComparison(_:)メソッドが呼び出される
2. state = .idleに変更
3. 選択状態をリセット

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

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

この画面ではローカルデータベースへの更新は行われない。

| 操作（イベント） | 対象 | 操作種別 | 概要 |
|----------------|------|---------|------|
| 履歴取得 | Wikipedia API | SELECT | ページ履歴の取得 |
| 編集統計取得 | Wikipedia API | SELECT | 編集回数・タイプ別統計の取得 |
| メトリクス取得 | Wikipedia API | SELECT | 時系列編集データの取得 |

## メッセージ仕様

| ID | 種別 | メッセージ内容 | 表示条件 |
|----|------|----------------|----------|
| MSG-01 | エラー | "No internet connection" | ネットワークエラー時 |
| MSG-02 | 警告 | "Maximum revisions selected" | 2つ選択後に追加選択しようとした場合 |

## 例外処理

| 例外条件 | 処理内容 |
|----------|----------|
| ネットワークエラー | WMFAlertManagerでエラー表示、VoiceOver対応 |
| APIエラー | エラーメッセージを表示 |

## 備考

- ColumnarCollectionViewControllerを継承しており、リスト表示の共通機能を再利用
- DiffRevisionRetrievingプロトコルを実装し、前後リビジョンの取得機能を提供
- EditHistoryCompareFunnelでユーザー行動をロギング
- セクションは日付でグループ化（今日の日付は相対表示）
- cellContentCacheでセル情報をキャッシュして再利用
- SelectionThemeModelで選択状態の色分け表示を管理

---

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

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

### 推奨読解順序

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

履歴データの構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | WMFPageHistoryRevision | `WMF Framework/WMFPageHistoryRevision.h` | リビジョンデータモデル（revisionID, user, revisionDate, revisionSize等） |
| 1-2 | PageHistorySection | `Wikipedia/Code/PageHistorySection.swift` | セクションデータ（sectionTitle, items） |

**読解のコツ**: WMFPageHistoryRevisionの各プロパティがセルの表示項目に対応していることを理解する。

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

PageHistoryViewControllerの初期化とデータ取得を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | PageHistoryViewController.swift | `Wikipedia/Code/PageHistoryViewController.swift` | 行56-68: init, 行164-182: viewDidLoad |

**主要処理フロー**:
1. **行56-63**: init - pageTitle, pageURL, articleSummaryController, authenticationManagerを設定
2. **行164-182**: viewDidLoad - セル登録、比較選択VC設定、編集統計・履歴取得
3. **行188-259**: getEditCounts() - 編集統計の取得（総編集数、タイプ別、時系列）
4. **行307-327**: getPageHistory() - 履歴データの取得

#### Step 3: 比較モードの実装を理解する

状態管理と選択処理を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | PageHistoryViewController.swift | `Wikipedia/Code/PageHistoryViewController.swift` | 行88-128: State enum, state変更処理 |

**主要処理フロー**:
- **行88-91**: State enum（idle/editing）
- **行103-128**: stateのdidSet - UIの切り替え処理
- **行706-750**: didSelectItemAt - 選択処理
- **行559-614**: SelectionThemeModel - 選択時の色テーマ

#### Step 4: セル設定を理解する

PageHistoryCollectionViewCellの設定を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | PageHistoryViewController.swift | `Wikipedia/Code/PageHistoryViewController.swift` | 行462-537: configure(cell:for:at:) |

**主要処理フロー**:
- **行473-495**: キャッシュからのデータ復元
- **行496-528**: 新規データの設定（時刻、編集者、サイズ差分、コメント）

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

```
PageHistoryViewController
    │
    ├─ ColumnarCollectionViewController (継承)
    │      └─ UICollectionView
    │             ├─ Header: PageHistoryCountsView
    │             │      └─ 編集統計表示
    │             │
    │             └─ Cells: PageHistoryCollectionViewCell
    │                    └─ 各リビジョン情報
    │
    ├─ PageHistoryComparisonSelectionViewController (子VC)
    │      ├─ 選択ボタン1
    │      ├─ 選択ボタン2
    │      └─ 比較ボタン
    │
    ├─ PageHistoryFetcher
    │      ├─ fetchRevisionInfo() - 履歴取得
    │      ├─ fetchFirstRevision() - 初回編集取得
    │      ├─ fetchEditCounts() - 編集統計取得
    │      └─ fetchEditMetrics() - 時系列データ取得
    │
    ├─ DiffContainerViewController (遷移先)
    │      └─ 差分比較表示
    │
    └─ DiffRevisionRetrieving (プロトコル実装)
           ├─ retrievePreviousRevision()
           ├─ retrieveNextRevision()
           └─ refreshRevisions()
```

### データフロー図

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

pageTitle, pageURL ─────▶ PageHistoryFetcher
                              │
                              ├─▶ fetchFirstRevision()
                              │        └─▶ firstEditDate
                              │
                              ├─▶ fetchEditCounts()
                              │        └─▶ totalEditCount, editCountsGroupedByType
                              │
                              ├─▶ fetchEditMetrics()
                              │        └─▶ timeseriesOfEditsCounts
                              │
                              └─▶ fetchRevisionInfo()
                                       │
                                       └─▶ [PageHistorySection]
                                                │
                                                ▼
                                       UICollectionView
                                                │
                                                ▼
ユーザー操作 ─────────▶ 状態変更（idle/editing）
                                                │
                                                ├─▶ リビジョンタップ（idle）
                                                │        └─▶ DiffContainerVC（単一差分）
                                                │
                                                └─▶ 比較モード（editing）
                                                         ├─▶ 2リビジョン選択
                                                         └─▶ DiffContainerVC（比較差分）
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| PageHistoryViewController.swift | `Wikipedia/Code/PageHistoryViewController.swift` | ソース | 本画面のコントローラ |
| PageHistoryCollectionViewCell.swift | `Wikipedia/Code/PageHistoryCollectionViewCell.swift` | ソース | リビジョンセル |
| PageHistoryCountsView.swift | `Wikipedia/Code/PageHistoryCountsView.swift` | ソース | 編集統計ヘッダー |
| PageHistoryComparisonSelectionViewController.swift | `Wikipedia/Code/PageHistoryComparisonSelectionViewController.swift` | ソース | 比較選択UI |
| PageHistoryFetcher.swift | `Wikipedia/Code/PageHistoryFetcher.swift` | ソース | 履歴データ取得 |
| DiffContainerViewController.swift | `Wikipedia/Code/DiffContainerViewController.swift` | ソース | 差分比較画面 |
| WMFPageHistoryRevision.h | `WMF Framework/WMFPageHistoryRevision.h` | ソース | リビジョンデータモデル |
| PageHistorySection.swift | `Wikipedia/Code/PageHistorySection.swift` | ソース | セクションデータモデル |
| EditHistoryCompareFunnel.swift | `Wikipedia/Code/EditHistoryCompareFunnel.swift` | ソース | 分析ロギング |
| ColumnarCollectionViewController.swift | `Wikipedia/Code/ColumnarCollectionViewController.swift` | ソース | 親クラス |
