# 画面設計書 45-StorageAndSyncingSettings画面

## 概要

本ドキュメントはWikipedia iOSアプリにおけるストレージと同期設定画面（StorageAndSyncingSettingsViewController）の設計内容を記載したものです。

### 本画面の処理概要

StorageAndSyncingSettings画面は、リーディングリストの同期設定、保存済み記事の管理、オフラインストレージの操作を行うための画面です。ログインユーザーは、リーディングリストをWikimediaアカウントと同期することで、複数デバイス間で保存済み記事を共有できます。

**業務上の目的・背景**：ユーザーがオフラインでも記事を閲覧できるよう、記事のローカル保存機能を提供しています。また、ログインユーザーに対してはクラウド同期機能を提供し、デバイス間でのシームレスな読書体験を実現します。ストレージ容量の管理として、保存済み記事を一括削除する機能も備えています。

**画面へのアクセス方法**：設定画面（Settings）から「Storage and syncing」項目をタップすることでこの画面に遷移します。

**主要な操作・処理内容**：
1. リーディングリスト同期のオン/オフ切り替え
2. デフォルト（Saved）リーディングリストの表示/非表示切り替え
3. 全保存済み記事の削除
4. サーバーとの同期更新リクエスト

**画面遷移**：
- 遷移元：Settings画面
- 遷移先：ログイン/アカウント作成パネル（未ログイン時の同期有効化）

**権限による表示制御**：
- 同期機能は永続ログイン（permanent login）状態のユーザーにのみ完全に利用可能
- 未ログインユーザーが同期を有効化しようとすると、ログインパネルを表示

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 49 | ストレージ・同期設定 | 主機能 | オフラインストレージと同期の設定 |

## 画面種別

設定（スイッチ切替型設定画面 + アクションボタン）

## URL/ルーティング

iOSネイティブアプリのため、URLは使用しない。画面遷移はUINavigationControllerのpush遷移で管理。

## 入出力項目

| 項目名 | 項目ID | データ型 | 入力/出力 | 必須 | 説明 |
|--------|--------|----------|-----------|------|------|
| 同期有効 | isSyncEnabled | Bool | 入出力 | - | リーディングリスト同期の有効/無効 |
| デフォルトリスト表示 | isDefaultListEnabled | Bool | 入出力 | - | Savedリストの表示/非表示 |
| キャッシュサイズ | totalCacheSizeInBytes | Int64 | 出力 | - | 保存済み記事の総サイズ |

## 表示項目

| 項目名 | データ型 | 説明 |
|--------|----------|------|
| ナビゲーションタイトル | String | "Storage and syncing" |
| Sync saved articles and lists | Switch | 同期有効/無効 |
| Show Saved reading list | Switch | デフォルトリスト表示 |
| Erase all saved articles | Button | 全記事削除ボタン |
| Update synced reading lists | Button | 同期更新ボタン |
| キャッシュサイズ表示 | String | "about X MB of space" |

## イベント仕様

### 1-同期スイッチ切替

リーディングリスト同期のオン/オフを切り替える際の処理。

1. `settingsTableViewCell(_:didToggleDisclosureSwitch:)`が呼び出される
2. ItemType.syncSavedArticlesAndListsを検出
3. authStateIsPermanentを確認
   - false: ログインパネルを表示、キャンセル時はスイッチを戻す
   - true: オン→同期有効化、オフ→確認パネル後に同期無効化
4. `dataStore.readingListsController.setSyncEnabled(_:shouldDeleteLocalLists:shouldDeleteRemoteLists:)`を実行
5. SettingsFunnelでログ記録

### 2-デフォルトリスト表示スイッチ切替

Savedリストの表示/非表示を切り替える際の処理。

1. `settingsTableViewCell(_:didToggleDisclosureSwitch:)`が呼び出される
2. ItemType.showSavedReadingListを検出
3. `dataStore.readingListsController.isDefaultListEnabled`を更新

### 3-全記事削除ボタンタップ

保存済み記事を一括削除する際の処理。

1. `eraseSavedArticles()`が呼び出される
2. 確認アラートを表示
3. 「Erase」選択時、`dataStore.readingListsController.eraseAllSavedArticlesAndReadingLists()`を実行
4. TableViewを再読み込み

### 4-同期更新ボタンタップ

サーバーと同期を更新する際の処理。

1. `tableView(_:didSelectRowAt:)`が呼び出される
2. ItemType.syncWithTheServerを検出
3. 認証状態を確認
   - 永続ログイン中かつ同期有効: `dataStore.readingListsController.fullSync({})`を実行
   - 永続ログイン中かつ同期無効: 同期有効化パネルを表示
   - 未ログイン: ログインパネルを表示

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| 同期有効化 | UserDefaults/CoreData | UPDATE | 同期設定を更新 |
| 同期無効化 | UserDefaults/CoreData | UPDATE/DELETE | 同期設定更新、リモートリスト削除 |
| デフォルトリスト切替 | UserDefaults | UPDATE | 表示設定を更新 |
| 全記事削除 | CoreData/ファイルシステム | DELETE | 保存済み記事とリーディングリストを削除 |
| 同期更新 | CoreData | UPDATE | サーバーからリストを同期 |

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

#### UserDefaults

| 操作 | 項目（キー名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | isSyncEnabled | Bool | 同期有効/無効 |
| UPDATE | isDefaultListEnabled | Bool | デフォルトリスト表示 |

#### CoreData (ReadingListsController経由)

| 操作 | 項目 | 更新値・取得条件 | 備考 |
|-----|------|-----------------|------|
| DELETE | ReadingList | - | 全リスト削除時 |
| DELETE | ReadingListEntry | - | 全記事削除時 |
| UPDATE | ReadingList | サーバーから取得 | 同期時 |

## メッセージ仕様

| メッセージID | 種別 | メッセージ内容 | 表示条件 |
|-------------|------|---------------|----------|
| settings-storage-and-syncing-enable-sync-title | ラベル | "Sync saved articles and lists" | 同期設定項目 |
| settings-storage-and-syncing-enable-sync-footer-text | フッター | "Allow Wikimedia to save your saved articles and reading lists to your user preferences when you login and sync." | 同期設定 |
| settings-storage-and-syncing-show-default-reading-list-title | ラベル | "Show Saved reading list" | デフォルトリスト設定 |
| settings-storage-and-syncing-show-default-reading-list-footer-text | フッター | "Show the Saved (eg. default) reading list as a separate list in your reading lists view..." | デフォルトリスト設定 |
| settings-storage-and-syncing-server-sync-title | ラベル | "Update synced reading lists" | 同期更新ボタン |
| settings-storage-and-syncing-server-sync-footer-text | フッター | "Request an update to your synced articles and reading lists." | 同期更新 |
| settings-storage-and-syncing-erase-saved-articles-alert-title | アラート | "Erase all saved articles?" | 削除確認 |
| settings-storage-and-syncing-erase-saved-articles-alert-message | アラート | "Erasing your saved articles will remove them from your user account..." | 削除確認 |
| settings-storage-and-syncing-full-sync | アラート | "Your reading lists will be synced in the background" | 同期開始通知 |

## 例外処理

| 例外条件 | 処理内容 |
|---------|---------|
| dataStoreがnil | assertionFailure発生、処理中断 |
| 未ログインで同期有効化 | ログインパネルを表示 |
| 同期無効化時 | 確認パネル表示後に処理実行 |

## 備考

- 本画面はSubSettingsViewControllerを継承
- ReadingListsController.readingListsServerDidConfirmSyncWasEnabledForAccountNotificationを監視して同期状態を更新
- EraseSavedArticlesViewはNibから読み込まれるカスタムビュー
- キャッシュサイズはCacheController.totalCacheSizeInBytesから取得
- ByteCountFormatterでサイズを人間が読みやすい形式に変換

---

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

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

### 推奨読解順序

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

まず、設定項目を表現するデータ構造を理解することが重要です。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | StorageAndSyncingSettingsViewController.swift | `Wikipedia/Code/StorageAndSyncingSettingsViewController.swift` | Section構造体とItem構造体（3-60行目） |
| 1-2 | StorageAndSyncingSettingsViewController.swift | `Wikipedia/Code/StorageAndSyncingSettingsViewController.swift` | ItemType列挙型（62-64行目） |

**読解のコツ**: ItemTypeが各設定項目の種別を定義し、Item構造体がその表示情報と状態を保持します。

#### Step 2: セクション構築を理解する

設定画面のセクション構成を確認します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | StorageAndSyncingSettingsViewController.swift | `Wikipedia/Code/StorageAndSyncingSettingsViewController.swift` | sections計算プロパティ（73-85行目） |

**主要処理フロー**:
1. **74行目**: 同期スイッチ項目の生成、isSyncEnabledで現在値を取得
2. **75行目**: デフォルトリスト表示スイッチの生成
3. **76行目**: 全記事削除項目の生成
4. **77行目**: 同期更新ボタン項目の生成
5. **79-82行目**: 各セクションの生成
6. **84行目**: 全セクションを配列で返却

#### Step 3: セル表示処理を理解する

TableViewのセル生成を確認します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | StorageAndSyncingSettingsViewController.swift | `Wikipedia/Code/StorageAndSyncingSettingsViewController.swift` | tableView(_:cellForRowAt:)（212-244行目） |

**主要処理フロー**:
- **215-230行目**: disclosureTypeがnilの場合（eraseSavedArticles）、EraseSavedArticlesViewを埋め込み
- **232-243行目**: 通常のWMFSettingsTableViewCellを構成

#### Step 4: スイッチ操作のハンドリングを理解する

ユーザーがスイッチを操作した際の処理フローを確認します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | StorageAndSyncingSettingsViewController.swift | `Wikipedia/Code/StorageAndSyncingSettingsViewController.swift` | settingsTableViewCell(_:didToggleDisclosureSwitch:)（295-340行目） |

**主要処理フロー**:
- **296-298行目**: ItemTypeの取得とdataStoreの確認
- **307-317行目**: 未ログイン時の同期有効化処理（ログインパネル表示）
- **318-333行目**: ログイン済み時の同期有効化/無効化処理
- **334-335行目**: デフォルトリスト表示スイッチの処理

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

```
StorageAndSyncingSettingsViewController
    │
    ├─ viewDidLoad()
    │      ├─ tableView.register() - セル登録
    │      └─ NotificationCenter.addObserver() - 同期通知監視
    │
    ├─ sections（計算プロパティ）
    │      ├─ syncSavedArticlesAndLists項目
    │      ├─ showSavedReadingList項目
    │      ├─ eraseSavedArticles項目
    │      └─ syncWithTheServer項目
    │
    ├─ tableView(_:cellForRowAt:)
    │      ├─ eraseSavedArticles → EraseSavedArticlesView埋め込み
    │      └─ その他 → WMFSettingsTableViewCell
    │
    ├─ settingsTableViewCell(_:didToggleDisclosureSwitch:)
    │      ├─ syncSavedArticlesAndLists
    │      │      ├─ 未ログイン → ログインパネル表示
    │      │      └─ ログイン済み → setSyncEnabled()
    │      └─ showSavedReadingList
    │             └─ isDefaultListEnabled = isSwitchOn
    │
    ├─ tableView(_:didSelectRowAt:)
    │      └─ syncWithTheServer
    │             ├─ 永続ログイン+同期有効 → fullSync()
    │             ├─ 永続ログイン+同期無効 → 同期有効化パネル
    │             └─ 未ログイン → ログインパネル
    │
    └─ eraseSavedArticles()
           ├─ 確認アラート表示
           └─ eraseAllSavedArticlesAndReadingLists()
```

### データフロー図

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

同期スイッチオン ─────────▶ settingsTableViewCell ────────▶ ReadingListsController
(未ログイン時)               (_:didToggleDisclosureSwitch:)       │
      │                              │                            ▼
      │                              ▼                    ログインパネル表示
      │                       authStateIsPermanent?               │
      │                              │                            ▼
      ▼                              ▼                    ログイン成功後
同期スイッチオン ─────────▶ setSyncEnabled(true) ─────────▶ サーバー同期開始
(ログイン済み)

全記事削除 ───────────────▶ eraseSavedArticles() ─────────▶ CoreData削除
      │                              │                     ファイルシステム削除
      │                              ▼
      │                       確認アラート
      │                              │
      ▼                              ▼
ユーザー確認 ─────────────▶ eraseAllSavedArticlesAndReadingLists()
                                     │
                                     ▼
                              キャッシュサイズ更新
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| StorageAndSyncingSettingsViewController.swift | `Wikipedia/Code/StorageAndSyncingSettingsViewController.swift` | ソース | メインのViewController |
| SubSettingsViewController.swift | `Wikipedia/Code/SubSettingsViewController.swift` | ソース | 親クラス（設定画面共通基盤） |
| EraseSavedArticlesView.swift | `Wikipedia/Code/EraseSavedArticlesView.swift` | ソース | 削除ボタンカスタムビュー |
| EraseSavedArticlesView.xib | `Wikipedia/Code/EraseSavedArticlesView.xib` | NIB | 削除ビューのレイアウト |
| ReadingListsController.swift | `WMF/Sources/WMF/Controllers/ReadingListsController.swift` | ソース | リーディングリスト管理 |
| CacheController.swift | `WMF/Sources/WMF/Controllers/CacheController.swift` | ソース | キャッシュ管理 |
| SettingsFunnel.swift | `Wikipedia/Code/SettingsFunnel.swift` | ソース | 設定操作ログ記録 |
