# 機能設計書 57-アプリ設定

## 概要

本ドキュメントは、InvenTreeモバイルアプリにおけるアプリ設定機能の設計を記述する。

### 本機能の処理概要

アプリの動作設定（ダークモード、言語、画面向き、ラベル印刷、HTTPS設定、サウンド、エラーレポート）を管理する機能を提供する。

**業務上の目的・背景**：モバイルアプリは様々な環境・条件で使用されるため、ユーザーごとにカスタマイズ可能な設定機能が必要である。ダークモードは照明環境や好みに応じた画面表示を提供し、言語設定は多国籍チームでの利用を可能にする。画面向きの固定は、スキャナー使用時など特定の操作環境に対応する。これらの設定により、ユーザー体験が向上し、業務効率が改善される。

**機能の利用シーン**：設定画面からアプリ設定メニューを選択してアプリ設定画面へ遷移する。各設定項目のスイッチやタップで設定値を変更し、即座に反映される。

**主要な処理内容**：
1. 現在の設定値をローカルDBから読み込む
2. 設定項目をListTile形式で表示する
3. スイッチやダイアログで設定値を変更する
4. 変更をローカルDBに永続化する
5. 必要に応じてアプリ全体に設定を反映する

**関連システム・外部連携**：ローカルDB（Sembast）、AdaptiveTheme（テーマ管理）、多言語対応機能との連携を行う。

**権限による制御**：認証は不要。アプリレベルの設定はユーザーが自由に変更可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 6 | 設定画面 | 遷移先機能 | アプリ設定メニュー押下時にアプリ設定画面へ遷移 |
| 10 | アプリ設定画面 | 主機能 | ダークモード、言語、エラーレポートなどの設定変更 |
| 2 | ドロワーメニュー | 遷移先機能 | 設定メニュー押下時に設定画面へ遷移 |

## 機能種別

設定管理 / CRUD操作

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| barcodeSounds | bool | - | バーコードサウンド有効/無効 | - |
| serverSounds | bool | - | サーバーエラーサウンド有効/無効 | - |
| reportErrors | bool | - | エラーレポート有効/無効 | - |
| strictHttps | bool | - | 厳密HTTPS検証有効/無効 | - |
| enableLabelPrinting | bool | - | ラベル印刷有効/無効 | - |
| darkMode | bool | - | ダークモード有効/無効 | - |
| screenOrientation | int | - | 画面向き（0:システム/1:縦/2:横） | 0-2 |
| locale | Locale | - | 言語設定 | サポート言語リスト内 |

### 入力データソース

- ユーザー操作（スイッチ、ダイアログ選択）
- ローカルDB（初期値読み込み）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 設定値 | dynamic | 各設定項目の値 |

### 出力先

- ローカルDB（Sembast）
- 画面表示（設定状態の反映）
- アプリ全体（テーマ、言語等の反映）

## 処理フロー

### 処理シーケンス

```
1. 画面初期化
   └─ initStateでloadSettings()呼び出し
2. 設定読み込み
   └─ InvenTreeSettingsManager().getValue()で各設定値取得
3. UI表示
   └─ ListView内にListTile配置
4. 設定変更
   ├─ Switch操作 → setValue()でDB保存 → setState()
   ├─ 言語選択 → launchApiForm() → setSelectedLocale()
   └─ 画面向き → choiceDialog() → setValue()
5. アプリ反映
   ├─ ダークモード → AdaptiveTheme.setDark/setLight()
   ├─ 言語 → InvenTreeApp.setLocale()
   └─ 画面向き → OS設定に連動
```

### フローチャート

```mermaid
flowchart TD
    A[アプリ設定画面表示] --> B[loadSettings]
    B --> C[ローカルDBから設定読込]
    C --> D[ListView表示]
    D --> E{設定操作}
    E -->|スイッチ| F[setValue + setState]
    E -->|言語選択| G[launchApiForm]
    E -->|画面向き| H[choiceDialog]
    F --> I[ローカルDB保存]
    G --> J[setSelectedLocale]
    H --> I
    J --> K[InvenTreeApp.setLocale]
    I --> L{追加処理必要?}
    L -->|ダークモード| M[AdaptiveTheme変更]
    L -->|言語| N[clearStatusCodeData]
    L -->|その他| O[処理完了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-57-01 | 即時反映 | 設定変更は即座にUIに反映 | 設定変更時 |
| BR-57-02 | 永続化 | 設定はローカルDBに保存され、アプリ再起動後も維持 | 設定変更時 |
| BR-57-03 | デフォルト値 | 未設定の場合はデフォルト値を使用 | 設定読込時 |
| BR-57-04 | 言語切替 | 言語変更時はステータスコードキャッシュをクリア | 言語変更時 |

### 計算ロジック

該当なし

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 設定読込 | settings | SELECT | 各設定値の取得 |
| 設定保存 | settings | UPDATE | 設定値の永続化 |

### テーブル別操作詳細

#### settings（Sembast）

| 操作 | 項目（キー） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| GET | INV_SOUNDS_BARCODE | bool | デフォルト: true |
| GET | INV_SOUNDS_SERVER | bool | デフォルト: true |
| GET | INV_REPORT_ERRORS | bool | デフォルト: true |
| GET | INV_STRICT_HTTPS | bool | デフォルト: false |
| GET | INV_SCREEN_ORIENTATION | int | デフォルト: 0 |
| GET | INV_ENABLE_LABEL_PRINTING | bool | デフォルト: true |
| GET | customLocale | String | デフォルト: "" |
| SET | 各キー | ユーザー入力値 | 即時保存 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | DB読込エラー | Sembast読込失敗 | デフォルト値を使用 |

### リトライ仕様

エラー発生時は画面を再表示することで再試行可能

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

各設定は独立して保存。トランザクション制御なし。

## パフォーマンス要件

- 設定読込は1秒以内
- 設定変更は即座に反映

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

- 設定はローカルDBに暗号化なしで保存
- strictHttps設定により証明書検証の厳密さを制御

## 備考

AdaptiveThemeパッケージでダークモード/ライトモードを管理。flutter_localized_localesパッケージで言語名を表示。

---

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

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

### 推奨読解順序

#### Step 1: 設定キー定義を理解する

設定項目のキー定数を確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | preferences.dart | `lib/preferences.dart` | 設定キー定数の定義 |

**読解のコツ**: INV_から始まる定数が設定キー。各設定の用途をコメントから理解する。

**主要処理フロー**:
- **10-16行目**: ホーム画面設定キー
- **18-23行目**: 画面向き定数
- **25-26行目**: サウンド設定キー
- **29-32行目**: ラベル印刷設定キー
- **53-54行目**: エラーレポート、HTTPS設定キー
- **57-63行目**: バーコード設定キー

#### Step 2: ウィジェット構造を理解する

アプリ設定画面の構造を確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | app_settings.dart | `lib/settings/app_settings.dart` | InvenTreeAppSettingsWidget |

**主要処理フロー**:
- **19-22行目**: StatefulWidgetの定義
- **24-41行目**: 状態変数の定義
- **44-47行目**: initStateでloadSettings呼び出し
- **50-87行目**: loadSettings()で設定値読込
- **143-350行目**: build()でUI構築

#### Step 3: 設定項目の実装を理解する

個々の設定項目の実装を確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | app_settings.dart | `lib/settings/app_settings.dart` | ListView内の各ListTile |

**主要処理フロー**:
- **183-199行目**: ダークモード設定
- **200-251行目**: 画面向き設定
- **252-268行目**: ラベル印刷設定
- **269-282行目**: 厳密HTTPS設定
- **283-290行目**: 言語設定
- **291-304行目**: エラーレポート設定
- **313-343行目**: サウンド設定

#### Step 4: 言語選択処理を理解する

言語設定のダイアログ処理を確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | app_settings.dart | `lib/settings/app_settings.dart` | _selectLocale()メソッド |

**主要処理フロー**:
- **89-140行目**: _selectLocale()メソッド
- **90-100行目**: 言語オプションリスト構築
- **102-109行目**: フォームフィールド定義
- **111-139行目**: launchApiForm()とonSuccess処理

#### Step 5: 設定永続化を理解する

設定の保存・読込を確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | preferences.dart | `lib/preferences.dart` | InvenTreeSettingsManager |

**主要処理フロー**:
- **110-185行目**: InvenTreeSettingsManagerクラス
- **146-159行目**: getValue()メソッド
- **175-180行目**: setValue()メソッド
- **121-140行目**: getSelectedLocale(), setSelectedLocale()

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

```
InvenTreeAppSettingsWidget (app_settings.dart)
    │
    └─ _InvenTreeAppSettingsState
           │
           ├─ initState()
           │      └─ loadSettings()
           │             └─ InvenTreeSettingsManager().getValue()
           │                    └─ Sembast DB読込
           │
           ├─ build()
           │      └─ ListView
           │             ├─ ListTile (ダークモード)
           │             │      └─ AdaptiveTheme.setDark/setLight()
           │             │
           │             ├─ ListTile (画面向き)
           │             │      └─ choiceDialog()
           │             │             └─ setValue()
           │             │
           │             ├─ ListTile (言語)
           │             │      └─ _selectLocale()
           │             │             └─ launchApiForm()
           │             │                    └─ setSelectedLocale()
           │             │                           └─ InvenTreeApp.setLocale()
           │             │
           │             └─ ListTile (その他)
           │                    └─ setValue()
           │
           └─ setState()
```

### データフロー図

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

initState       ───▶  loadSettings()              ───▶  UI状態更新
                          │
                          └─ getValue() x N
                                 └─ Sembast DB
                                        │
                                        ▼
スイッチ操作    ───▶  onChanged                   ───▶  設定変更
                          │
                          ├─ setValue()
                          │      └─ Sembast DB書込
                          │
                          ├─ setState()
                          │
                          └─ (オプション)
                                 ├─ AdaptiveTheme変更
                                 └─ setLocale()
                                        └─ アプリ全体に反映
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| app_settings.dart | `lib/settings/app_settings.dart` | ソース | アプリ設定画面 |
| preferences.dart | `lib/preferences.dart` | ソース | 設定キー定義・永続化 |
| l10.dart | `lib/l10.dart` | ソース | 多言語対応 |
| main.dart | `lib/main.dart` | ソース | InvenTreeApp（setLocale） |
| dialogs.dart | `lib/widget/dialogs.dart` | ソース | choiceDialog |
| api_form.dart | `lib/api_form.dart` | ソース | launchApiForm |
