# 機能設計書 5-記事共有

## 概要

本ドキュメントは、Wikipedia iOSアプリにおける記事共有機能の設計仕様を記述する。iOSの標準共有シート（UIActivityViewController）を使用して、記事のURLやテキスト、画像を外部アプリと共有する。

### 本機能の処理概要

**業務上の目的・背景**：ユーザーがWikipediaで発見した興味深い情報を、SNS、メール、メッセージなどの外部サービスを通じて他者と共有できるようにする。また、「Share-a-fact」機能により、記事内の選択テキストを引用画像として共有することも可能。

**機能の利用シーン**：
- 記事画面のツールバーから共有ボタンをタップした時
- 記事プレビューのコンテキストメニューから共有を選択した時
- 記事内のテキストを選択して共有した時
- 画像ギャラリーから画像を共有した時
- リーディングリストから記事を共有した時

**主要な処理内容**：
1. 共有対象データ（URL、テキスト、画像）の準備
2. カスタムアクティビティ（リーディングリスト追加、Share-a-fact）の追加
3. UIActivityViewControllerの表示
4. 共有先アプリへのデータ引き渡し

**関連システム・外部連携**：
- UIActivityViewController（iOSの標準共有フレームワーク）
- Safari（Safariで開くアクション）
- Maps（地図で開く、経路案内アクション）
- 各種SNS、メールアプリ等

**権限による制御**：
- 特別な権限は不要

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 9 | Share画面 | 主画面 | 共有シートの表示、共有先選択 |
| 5 | Article画面 | 呼び出し元 | 記事の共有トリガー |
| 6 | ArticlePeekPreview画面 | 呼び出し元 | プレビューからの共有 |

## 機能種別

表示処理 / インタラクション / 外部連携

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| article | WMFArticle | Yes | 共有対象の記事 | nil不可 |
| customActivities | [UIActivity] | No | カスタムアクティビティ | 空配列許容 |
| textActivitySource | WMFArticleTextActivitySource | No | テキスト共有ソース | nil許容 |
| image | UIImage | No | 共有する画像 | nil許容 |
| title | String | No | 共有タイトル | nil許容 |

### 共有対象データ

| データ種別 | 説明 | 例 |
|-----------|------|-----|
| テキスト | 記事タイトル | "\"日本\" on Wikipedia" |
| URL | 記事のURL（フラグメント付き） | https://ja.wikipedia.org/wiki/日本#歴史 |
| MKMapItem | 位置情報（記事に位置情報がある場合） | - |
| 画像 | 選択した画像（画像共有時） | - |

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 共有シート | UIActivityViewController | 共有オプションを表示するUI |

### 出力先

- 外部アプリ（Safari、Messages、Mail、SNS等）

## 処理フロー

### 処理シーケンス

```
1. 共有トリガー検出
   └─ ツールバーの共有ボタンタップ
   └─ コンテキストメニューから共有選択
   └─ 選択テキストから共有

2. 共有データの準備
   └─ 記事タイトルからテキスト生成
   └─ 記事URLの取得（フラグメント付き）
   └─ 位置情報（MKMapItem）の取得（あれば）

3. カスタムアクティビティの準備
   └─ AddToReadingListActivity
   └─ MoveToReadingListActivity（リーディングリスト詳細画面から）
   └─ CustomShareActivity（Share-a-fact）

4. ShareActivityControllerの生成
   └─ activityItemsにデータを設定
   └─ applicationActivitiesにカスタムアクティビティを設定
   └─ excludedActivityTypesに.addToReadingListを設定

5. 共有シートの表示
   └─ iPad: popoverPresentationControllerの設定
   └─ present(shareActivityController, animated: true)

6. ユーザーによる共有先選択
   └─ 標準アクション: システムが処理
   └─ カスタムアクション: perform()が呼び出される
```

### フローチャート

```mermaid
flowchart TD
    A[共有ボタンタップ] --> B[共有データ準備]
    B --> C{選択テキストあり?}
    C -->|Yes| D[テキスト共有モード]
    C -->|No| E[標準共有モード]
    D --> F[ShareActivityController生成]
    E --> F
    F --> G[カスタムアクティビティ追加]
    G --> H{iPad?}
    H -->|Yes| I[popover設定]
    H -->|No| J[モーダル表示]
    I --> K[共有シート表示]
    J --> K
    K --> L{ユーザー選択}
    L -->|標準アクション| M[システム処理]
    L -->|カスタムアクション| N[perform()実行]
    L -->|キャンセル| O[閉じる]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | テキスト形式 | 共有テキストは「"タイトル" on Wikipedia」形式 | 常時 |
| BR-002 | URL形式 | 共有URLはwmf_URLForTextSharing形式 | テキスト共有時 |
| BR-003 | 画像URL形式 | 画像共有時はwmf_URLForImageSharing形式 | 画像共有時 |
| BR-004 | iPad対応 | iPadではpopover形式で表示 | UIDevice.current.userInterfaceIdiom == .pad |
| BR-005 | システム除外 | システムのaddToReadingListは除外 | 常時（カスタム版を使用） |

### 標準アプリケーションアクティビティ

| アクティビティ | クラス | 説明 |
|--------------|-------|------|
| Safariで開く | TUSafariActivity | URLをSafariで開く |
| 地図で開く | WMFOpenInMapsActivity | 位置情報をMapで開く |
| 経路案内 | WMFGetDirectionsInMapsActivity | 位置情報への経路を表示 |

### カスタムアクティビティ

| アクティビティ | クラス | 説明 |
|--------------|-------|------|
| リーディングリストに追加 | AddToReadingListActivity | リーディングリストに保存 |
| リーディングリストへ移動 | MoveToReadingListActivity | 別のリストへ移動 |
| Share-a-fact | CustomShareActivity | 引用画像として共有 |

## データベース操作仕様

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| なし | - | - | 共有自体はDB操作なし |
| リーディングリスト追加 | ReadingList | INSERT | カスタムアクション経由 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 記事取得失敗 | articleがnil | 共有シートを表示しない |
| - | URL取得失敗 | URLが生成できない | URLなしで共有 |

### リトライ仕様

- 特別なリトライ処理なし

## トランザクション仕様

- トランザクション処理なし（リーディングリスト追加は別機能）

## パフォーマンス要件

- 共有シート表示までの目標時間：0.5秒以内

## セキュリティ考慮事項

- 共有データはユーザーが明示的に選択した内容のみ
- 外部アプリへの送信はiOSの標準共有フレームワークを使用

## 備考

- Share-a-factは選択テキストを引用カードとして画像化する機能

---

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

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

### 推奨読解順序

#### Step 1: 共有コントローラーを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | ShareActivityController.swift | `Wikipedia/Code/ShareActivityController.swift` | 共有シートのメインクラス |

**主要コード**:
- **133-157行目**: `ShareActivityController` - UIActivityViewControllerのサブクラス
- **136行目**: articleApplicationActivities - 標準アプリアクティビティ
- **138-157行目**: init(article:customActivities:) - 基本イニシャライザ
- **159-175行目**: init(customActivities:article:textActivitySource:) - テキスト共有用イニシャライザ
- **194-213行目**: init(article:image:title:) - 画像共有用イニシャライザ

#### Step 2: カスタムアクティビティを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | ShareActivityController.swift | `Wikipedia/Code/ShareActivityController.swift` | カスタムアクティビティ定義 |

**主要コード**:
- **4-31行目**: `CustomShareActivity` - 汎用カスタムアクティビティ
- **84-106行目**: `AddToReadingListActivity` - リーディングリスト追加
- **108-131行目**: `MoveToReadingListActivity` - リーディングリスト間移動

**読解のコツ**: UIActivityのサブクラスでは`activityTitle`、`activityImage`、`perform()`をオーバーライドする。

#### Step 3: 共有プロトコルを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | ShareActivityController.swift | `Wikipedia/Code/ShareActivityController.swift` | ShareableArticlesProviderプロトコル |

**主要コード**:
- **33-81行目**: `ShareableArticlesProvider`プロトコルと拡張
- **37-50行目**: share(article:articleURL:...) - 共有エントリーポイント
- **52-80行目**: createAndPresentShareActivityController() - 共有コントローラー生成・表示

#### Step 4: ArticleViewControllerからの呼び出しを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | ArticleViewController+Sharing.swift | `Wikipedia/Code/ArticleViewController+Sharing.swift` | 記事画面からの共有 |

**主要処理**:
- **4-13行目**: shareArticle() - 選択テキストを取得して共有
- **15-33行目**: shareArticle(with:) - 共有アクティビティコントローラーを表示
- **35-45行目**: sharingActivityViewController() - 共有コントローラーの生成
- **47-52行目**: shareAFact() - Share-a-fact機能

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

```
ArticleViewController / 各種ViewController
    │
    ├─ shareArticle()
    │      └─ webView.wmf_getSelectedText()
    │             └─ shareArticle(with: selectedText)
    │
    ├─ sharingActivityViewController()
    │      │
    │      └─ ShareActivityController
    │             │
    │             ├─ activityItems
    │             │      ├─ テキスト（"タイトル" on Wikipedia）
    │             │      ├─ URL（wmf_URLForTextSharing）
    │             │      └─ MKMapItem（位置情報あれば）
    │             │
    │             └─ applicationActivities
    │                    ├─ TUSafariActivity
    │                    ├─ WMFOpenInMapsActivity
    │                    ├─ WMFGetDirectionsInMapsActivity
    │                    ├─ AddToReadingListActivity
    │                    └─ CustomShareActivity (Share-a-fact)
    │
    └─ present(shareActivityController, animated: true)
```

### データフロー図

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

WMFArticle ─────────────▶ ShareActivityController
    │                          │
    ├─ displayTitle ──────▶    ├─ テキスト生成
    ├─ url ───────────────▶    ├─ URL生成
    └─ mapItem ───────────▶    └─ 位置情報追加
                               │
customActivities ─────────▶    │ (アクティビティ追加)
                               │
                               ▼
                         UIActivityViewController
                               │
                               ▼
                         [共有シート表示]
                               │
                               ▼
                         外部アプリへ共有
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| ShareActivityController.swift | `Wikipedia/Code/` | ソース | 共有シートメインクラス |
| ArticleViewController+Sharing.swift | `Wikipedia/Code/` | ソース | 記事画面の共有拡張 |
| ShareViewController.swift | `Wikipedia/Code/` | ソース | Share-a-fact画面 |
| WMFArticleTextActivitySource.swift | `Wikipedia/Code/` | ソース | テキスト共有ソース |
| WMFImageTextActivitySource.swift | `Wikipedia/Code/` | ソース | 画像テキスト共有ソース |
| WMFImageURLActivitySource.swift | `Wikipedia/Code/` | ソース | 画像URL共有ソース |
| TUSafariActivity.swift | `Wikipedia/Code/` | ソース | Safariで開くアクティビティ |
| WMFOpenInMapsActivity.swift | `Wikipedia/Code/` | ソース | 地図で開くアクティビティ |
| WMFGetDirectionsInMapsActivity.swift | `Wikipedia/Code/` | ソース | 経路案内アクティビティ |
