# Phase 4: ユーザビリティ向上 - 実装計画

**Version:** 1.0
**Date:** 2026-01-16
**Based on:** Antigravity's proposal + Claude's improvements
**Status:** Ready to implement

---

## Overview

Phase 4では以下2つの機能を実装します：
1. 🌙 **ダークモード自動切替** - 時間帯に応じた自動テーマ変更
2. 🖋️ **和風フォント対応** - 日本酒アプリにふさわしいフォント選択

---

## Feature 1: ダークモード自動切替 🌙

### 要件定義
- **既存**: ライト/ダーク/システム連動の3モード
- **追加**: 時間連動モード（夜間自動ダーク化）
- **切替時刻**: 20:00〜06:00 = ダークモード
- **ユーザー設定**: 設定画面で選択可能

### 技術仕様

#### A. ThemeMode拡張
```dart
enum AppThemeMode {
  light,      // 常にライト
  dark,       // 常にダーク
  system,     // OSに従う
  autoTime,   // 時間連動（新規）
}
```

#### B. 時刻判定ロジック
```dart
class ThemeProvider extends ChangeNotifier {
  AppThemeMode _themeMode = AppThemeMode.autoTime;

  // 現在適用すべきThemeModeを計算
  ThemeMode get effectiveThemeMode {
    if (_themeMode == AppThemeMode.autoTime) {
      final hour = DateTime.now().hour;
      // 20:00〜06:00 = ダークモード
      return (hour >= 20 || hour < 6) ? ThemeMode.dark : ThemeMode.light;
    }
    // その他のモードは既存ロジック
    return _themeModeToFlutterThemeMode(_themeMode);
  }
}
```

#### C. 自動更新メカニズム
**方式1: WidgetsBindingObserver（推奨）**
- アプリがバックグラウンドから復帰した時に再計算
- 電池消費が少ない
- リアルタイム性は低い（アプリを開いた時のみ）

**方式2: Timer**
- 1分ごとに時刻をチェック
- リアルタイム性が高い
- 電池消費がやや増える

**採用: 方式1（推奨）** - 日本酒アプリでは厳密なリアルタイム性は不要

```dart
class ThemeProvider extends ChangeNotifier with WidgetsBindingObserver {
  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    if (state == AppLifecycleState.resumed) {
      // アプリ復帰時にテーマを再計算
      notifyListeners();
    }
  }
}
```

#### D. UI実装
**設定画面の選択肢:**
```
○ ライトモード
○ ダークモード
○ システム設定に従う
● 自動（夜間ダーク） ← NEW
```

**現在の状態表示:**
```
テーマ: 自動（夜間ダーク）
現在: ダークモード（20:00〜06:00適用中）
```

### 実装ファイル

| ファイル | 変更内容 |
|---------|---------|
| `lib/providers/theme_provider.dart` | AppThemeMode enum追加、autoTime実装 |
| `lib/screens/settings_screen.dart` | 4つ目の選択肢追加、状態表示追加 |
| `lib/services/hive_service.dart` | autoTimeモードの永続化対応 |

### テスト計画

**1. 時刻判定テスト**
```dart
// テスト用時刻注入
class TimeService {
  static DateTime Function() now = () => DateTime.now();
}

// テストケース:
// 05:59 → ダーク
// 06:00 → ライト
// 19:59 → ライト
// 20:00 → ダーク
```

**2. UI動作テスト**
- [ ] 設定で「自動（夜間ダーク）」を選択できる
- [ ] 現在の適用状態が表示される
- [ ] アプリ再起動後も設定が保持される
- [ ] 時刻をまたいでアプリを開くとテーマが変わる

**3. パフォーマンステスト**
- [ ] 電池消費が増えていない
- [ ] アプリ復帰時の遅延がない

---

## Feature 2: 和風フォント対応 🖋️

### 要件定義
- **既存**: システムフォント（Noto Sans JP相当）
- **追加**: 日本酒らしい和風フォント
- **実装方式**: Google Fonts（動的読み込み）
- **ユーザー設定**: 設定画面で選択可能

### フォント候補

#### Option 1: Potta One（推奨 - Antigravity提案）
- **特徴**: 丸みがあり親しみやすい、読みやすい
- **サイズ**: ~2MB
- **用途**: メイン表示、カジュアルな雰囲気
- **プレビュー**: ぽんしゅルーム / 純米大吟醸

#### Option 2: Yuji Syuku
- **特徴**: 筆文字風、書道感が強い
- **サイズ**: ~1.5MB
- **用途**: タイトル、高級感演出
- **プレビュー**: ぽんしゅルーム / 純米大吟醸

#### Option 3: Shippori Mincho
- **特徴**: 明朝体、洗練された印象
- **サイズ**: ~3MB
- **用途**: フォーマルな表示、詳細画面
- **プレビュー**: ぽんしゅルーム / 純米大吟醸

#### Option 4: Zen Maru Gothic
- **特徴**: ゴシック体、モダン和風
- **サイズ**: ~2MB
- **用途**: 全般的な表示、バランス重視
- **プレビュー**: ぽんしゅルーム / 純米大吟醸

**初回実装: Potta One（1種類のみ）**
将来的に複数選択肢を追加可能な設計にする。

### 技術仕様

#### A. フォント定義
```dart
enum AppFontStyle {
  standard,  // システムフォント
  pottaOne,  // 丸文字（和風カジュアル）
  // 将来の拡張:
  // yujiSyuku,    // 筆文字
  // shipporiMincho, // 明朝体
}
```

#### B. テーマ適用
```dart
// app_theme.dart
class AppTheme {
  static ThemeData buildTheme({
    required Brightness brightness,
    required AppFontStyle fontStyle,
  }) {
    final TextTheme textTheme;

    switch (fontStyle) {
      case AppFontStyle.pottaOne:
        textTheme = GoogleFonts.pottaOneTextTheme();
        break;
      case AppFontStyle.standard:
      default:
        textTheme = const TextTheme(); // システムデフォルト
    }

    return ThemeData(
      brightness: brightness,
      textTheme: textTheme,
      // ... 既存の設定
    );
  }
}
```

#### C. Provider統合
```dart
class ThemeProvider extends ChangeNotifier {
  AppFontStyle _fontStyle = AppFontStyle.standard;

  void setFontStyle(AppFontStyle style) {
    _fontStyle = style;
    notifyListeners();
    // Hiveに保存
  }
}
```

#### D. UI実装
**設定画面の選択肢:**
```
フォント設定
○ 標準フォント
● 和風フォント（丸文字）

プレビュー:
┌─────────────────┐
│ ぽんしゅルーム    │ ← 実際のフォントで表示
│ 純米大吟醸       │
└─────────────────┘
```

### 実装ファイル

| ファイル | 変更内容 |
|---------|---------|
| `pubspec.yaml` | google_fonts: ^6.1.0（既存） |
| `lib/theme/app_theme.dart` | AppFontStyle対応、GoogleFonts統合 |
| `lib/providers/theme_provider.dart` | フォント設定管理 |
| `lib/screens/settings_screen.dart` | フォント選択UI追加 |
| `lib/services/hive_service.dart` | フォント設定の永続化 |

### パフォーマンス考慮

**初回読み込み:**
- Google Fontsは初回のみネットワークからダウンロード
- キャッシュに保存される（2回目以降は即座に表示）
- ダウンロード中はシステムフォントで表示（フォント切替時の一瞬のちらつき）

**オフライン対応（オプション）:**
```yaml
# pubspec.yaml
fonts:
  - family: PottaOne
    fonts:
      - asset: assets/fonts/PottaOne-Regular.ttf
```
- 事前にアセットとして含める（アプリサイズ +2MB）
- ネットワーク不要で即座に表示

**推奨: Google Fonts動的読み込み**（初回実装）
アプリサイズを増やさず、将来的に複数フォント追加が容易。

### テスト計画

**1. フォント適用テスト**
- [ ] 設定で「和風フォント」を選択できる
- [ ] 全画面でフォントが変わる（Home, Detail, Settings）
- [ ] PDFでもフォントが反映される ※重要
- [ ] アプリ再起動後も設定が保持される

**2. 読みやすさテスト**
- [ ] 短文（銘柄名）: 視認性OK
- [ ] 長文（説明文）: 読みやすさOK
- [ ] 小サイズ（10px〜）: 潰れない
- [ ] ダークモード: コントラストOK

**3. パフォーマンステスト**
- [ ] 初回読み込み時間: 3秒以内
- [ ] 2回目以降: 即座に表示
- [ ] アプリサイズ増加: 0MB（動的読み込み）

**4. PDF出力テスト**
- [ ] PDF生成時にPotta Oneが使用される
- [ ] PDFファイルサイズが適切（フォント埋め込み）
- [ ] 印刷時にフォントが正しく表示される

---

## 実装スケジュール

### Phase 4A: ダークモード自動切替（所要時間: 2-3時間）

**Step 1: Provider実装（30分）**
- [ ] `AppThemeMode` enum追加
- [ ] `effectiveThemeMode` ロジック実装
- [ ] `WidgetsBindingObserver` 統合

**Step 2: UI実装（30分）**
- [ ] 設定画面に「自動（夜間ダーク）」追加
- [ ] 現在の状態表示を追加

**Step 3: 永続化（30分）**
- [ ] Hiveに `autoTime` モード保存
- [ ] 起動時の復元処理

**Step 4: テスト（1時間）**
- [ ] 時刻判定テスト（モック使用）
- [ ] UI動作確認
- [ ] 実機で夜間動作確認

### Phase 4B: 和風フォント対応（所要時間: 2-3時間）

**Step 1: テーマ実装（30分）**
- [ ] `AppFontStyle` enum追加
- [ ] `AppTheme.buildTheme()` にフォント統合
- [ ] GoogleFonts.pottaOne() 適用

**Step 2: Provider実装（30分）**
- [ ] ThemeProviderにフォント設定追加
- [ ] setFontStyle() 実装

**Step 3: UI実装（30分）**
- [ ] 設定画面にフォント選択追加
- [ ] プレビュー表示

**Step 4: PDF対応（30分）**
- [ ] PdfService でフォント設定を参照
- [ ] Potta One をPDFに埋め込み

**Step 5: テスト（1時間）**
- [ ] 全画面でフォント確認
- [ ] PDF出力確認
- [ ] パフォーマンス計測

---

## リスク管理

### リスク1: Google Fonts読み込み失敗
**シナリオ**: ネットワーク不安定、サーバーダウン
**影響**: フォントがシステムフォントにフォールバック
**対策**:
- エラー時にユーザーに通知
- 次回起動時に再試行
- 最終的にはアセット埋め込みも検討

### リスク2: PDFフォント埋め込み失敗
**シナリオ**: `pdf` パッケージがGoogle Fontsをサポートしない
**影響**: PDFは標準フォントで生成される
**対策**:
- 事前に検証（PDF生成テスト）
- 必要ならTTFファイルを手動ダウンロードして埋め込み

### リスク3: ダークモード切替のタイミングずれ
**シナリオ**: アプリをバックグラウンドで長時間起動
**影響**: 20:00になってもライトモードのまま
**対策**:
- `WidgetsBindingObserver` で確実に検知
- 設定画面を開いた時も強制再計算

---

## 成果物

### コード変更
- `lib/providers/theme_provider.dart` (+50 lines)
- `lib/theme/app_theme.dart` (+30 lines)
- `lib/screens/settings_screen.dart` (+80 lines)
- `lib/services/hive_service.dart` (+20 lines)

### ドキュメント
- この実装計画書
- ユーザー向けリリースノート（後ほど作成）

### テスト結果レポート
- ダークモード自動切替の動作確認
- フォント適用の全画面スクリーンショット

---

## 次フェーズへの展望

### Phase 4C: フォント拡張（将来）
- 複数フォント選択肢（Yuji Syuku, Shippori Mincho）
- フォントサイズ調整（大/中/小）
- 部分的フォント適用（タイトルのみ和風、本文は標準）

### Phase 4D: テーマカスタマイズ（将来）
- カラーテーマ選択（青/緑/赤など）
- アクセントカラー変更
- カスタムテーマ保存

---

## 承認

**この計画で実装を開始してよろしいでしょうか？**

承認いただければ、Phase 4A（ダークモード）から実装を開始します。

---

**End of Plan**
