chore: guard DevMenu in release build, clean up Phase/TODO comments
- DevMenu: kReleaseModeのときonTap=nullでリリースビルドから完全無効化 - Phase N マーカーを全ファイルから削除(実装済みのため歴史的コメントを除去) - analysis_cache_service TODOを具体的な記述に改善 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
426697403e
commit
b6163e8efe
|
|
@ -40,7 +40,7 @@ class SakeItem extends HiveObject {
|
|||
@HiveField(25)
|
||||
ItemType? _itemType;
|
||||
|
||||
// --- Phase 1: Draft Mode Fields (Fields 26-27) ---
|
||||
// --- Draft Mode Fields (Fields 26-27) ---
|
||||
@HiveField(26)
|
||||
bool? _isPendingAnalysis; // true = AI解析待ち, false/null = 通常登録済み
|
||||
|
||||
|
|
@ -110,7 +110,7 @@ class SakeItem extends HiveObject {
|
|||
Gamification? gamification,
|
||||
Metadata? metadata,
|
||||
ItemType? itemType,
|
||||
// Phase 1: Draft Mode params
|
||||
// Draft Mode params
|
||||
bool? isPendingAnalysis,
|
||||
String? draftPhotoPath,
|
||||
// Legacy params for migration compatibility (optional)
|
||||
|
|
@ -216,7 +216,7 @@ class SakeItem extends HiveObject {
|
|||
_itemType = val;
|
||||
}
|
||||
|
||||
// Phase 1: Draft Mode Getters/Setters
|
||||
// Draft Mode Getters/Setters
|
||||
bool get isPendingAnalysis => _isPendingAnalysis ?? false;
|
||||
|
||||
set isPendingAnalysis(bool val) {
|
||||
|
|
@ -274,7 +274,7 @@ class SakeItem extends HiveObject {
|
|||
String? riceVariety,
|
||||
String? yeast,
|
||||
String? manufacturingYearMonth,
|
||||
// Phase 1: Draft Mode
|
||||
// Draft Mode
|
||||
bool? isPendingAnalysis,
|
||||
String? draftPhotoPath,
|
||||
}) {
|
||||
|
|
@ -322,7 +322,7 @@ class SakeItem extends HiveObject {
|
|||
aiConfidence: confidenceScore,
|
||||
),
|
||||
itemType: itemType ?? this.itemType,
|
||||
// Phase 1: Draft Mode
|
||||
// Draft Mode
|
||||
isPendingAnalysis: isPendingAnalysis ?? this.isPendingAnalysis,
|
||||
draftPhotoPath: draftPhotoPath ?? this.draftPhotoPath,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ class DisplayModeNotifier extends Notifier<String> {
|
|||
|
||||
@override
|
||||
String build() {
|
||||
// Phase 1 Optimization: Access box directly
|
||||
// SplashScreenで開済みのboxに直接アクセス
|
||||
_box = Hive.box<UserProfile>('user_profile');
|
||||
_profile = _box.get('current_user') ?? UserProfile(createdAt: DateTime.now());
|
||||
return _profile.displayMode;
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ class MenuOrderedIdsNotifier extends Notifier<List<String>> {
|
|||
}
|
||||
}
|
||||
|
||||
// 4. PDF Settings Providers (Phase 4)
|
||||
// 4. PDF Settings Providers
|
||||
// Note: We use Notifiers for complex logic, but simple StateProviders (Riverpod 2.0 style) are fine here.
|
||||
// Actually, Riverpod recommended is Notifier, but StateProvider is still available.
|
||||
// Let's use simple class-based Notifiers for 2.0 strictness if needed, or simple State for brevity.
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ class UserProfileNotifier extends Notifier<UserProfile> {
|
|||
|
||||
@override
|
||||
UserProfile build() {
|
||||
// Phase 1 Optimization: Access box directly as it's guaranteed to be open by SplashScreen
|
||||
// SplashScreenで開済みのboxに直接アクセス
|
||||
_box = Hive.box<UserProfile>('user_profile');
|
||||
|
||||
// Return existing profile or create default
|
||||
|
|
|
|||
|
|
@ -217,7 +217,7 @@ class _CameraScreenState extends ConsumerState<CameraScreen> with SingleTickerPr
|
|||
|
||||
final imagePath = compressedPath;
|
||||
|
||||
// Save to Gallery (Public) - Phase 4: Data Safety
|
||||
// Save to Gallery (Public)
|
||||
try {
|
||||
await Gal.putImage(imagePath);
|
||||
debugPrint('Saved to Gallery: $imagePath');
|
||||
|
|
|
|||
|
|
@ -21,9 +21,6 @@ class DevMenuScreen extends ConsumerWidget {
|
|||
),
|
||||
body: ListView(
|
||||
children: [
|
||||
// NOTE: 言語・テーマ選択は設定画面(SoulScreen)に移動済み
|
||||
// このメニューはUI実験・デバッグ機能のみ
|
||||
|
||||
const ListTile(
|
||||
leading: Icon(LucideIcons.flaskConical),
|
||||
title: Text('UI実験'),
|
||||
|
|
|
|||
|
|
@ -143,7 +143,7 @@ class HomeScreen extends ConsumerWidget {
|
|||
body: SafeArea(
|
||||
child: Column(
|
||||
children: [
|
||||
// Phase 1: 未解析Draft通知バナー
|
||||
// 未解析Draft通知バナー
|
||||
const PendingAnalysisBanner(),
|
||||
|
||||
if (!isMenuMode && hasItems)
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ class PdfPreviewScreen extends ConsumerWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
// Phase 4: Watch new PDF Settings
|
||||
// PDF Settings を監視
|
||||
final isPortrait = ref.watch(pdfIsPortraitProvider);
|
||||
final density = ref.watch(pdfDensityProvider);
|
||||
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ class _SakeDetailScreenState extends ConsumerState<SakeDetailScreen> {
|
|||
Widget build(BuildContext context) {
|
||||
final appColors = Theme.of(context).extension<AppColors>()!;
|
||||
|
||||
// スマートレコメンド (Phase 1-8 Enhanced)
|
||||
// スマートレコメンド
|
||||
final allSakeAsync = ref.watch(allSakeItemsProvider);
|
||||
final allSake = allSakeAsync.asData?.value ?? [];
|
||||
|
||||
|
|
@ -209,7 +209,7 @@ class _SakeDetailScreenState extends ConsumerState<SakeDetailScreen> {
|
|||
|
||||
const SizedBox(height: 48),
|
||||
|
||||
// Related Items 3D Carousel (Phase 1-8 Enhanced)
|
||||
// Related Items 3D Carousel
|
||||
if (_sake.itemType != ItemType.set) ...[ // Hide for Set Items
|
||||
Row(
|
||||
children: [
|
||||
|
|
@ -273,7 +273,7 @@ class _SakeDetailScreenState extends ConsumerState<SakeDetailScreen> {
|
|||
),
|
||||
),
|
||||
|
||||
// Phase 2-3: Business Pricing Section (Extracted)
|
||||
// Business Pricing Section
|
||||
SliverToBoxAdapter(
|
||||
child: SakePricingSection(
|
||||
sake: _sake,
|
||||
|
|
|
|||
|
|
@ -128,9 +128,7 @@ class AnalysisCacheService {
|
|||
/// - 30日経過したキャッシュは削除
|
||||
/// - 日本酒の仕様変更(リニューアル)に対応
|
||||
static Future<void> cleanupExpired() async {
|
||||
// TODO: 実装(Phase 3)
|
||||
// - キャッシュにタイムスタンプを追加
|
||||
// - 30日以上古いエントリを削除
|
||||
// TODO: キャッシュにタイムスタンプを追加し、30日以上古いエントリを削除する
|
||||
}
|
||||
|
||||
// ============================================
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import 'gemini_service.dart';
|
|||
|
||||
/// Draft(解析待ちアイテム)管理サービス
|
||||
///
|
||||
/// Phase 1緊急対応: オフライン時に撮影した写真を一時保存し、
|
||||
/// オフライン時に撮影した写真を一時保存し、
|
||||
/// オンライン復帰時に自動解析する機能を提供します。
|
||||
///
|
||||
/// 使用フロー:
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ class GeminiService {
|
|||
|
||||
/// 画像リストから日本酒ラベルを解析
|
||||
Future<SakeAnalysisResult> analyzeSakeLabel(List<String> imagePaths, {bool forceRefresh = false}) async {
|
||||
// Force use of client-side prompt to ensure Schema consistency (Phase 1 Fix)
|
||||
// クライアント側プロンプトでスキーマの一貫性を保証
|
||||
const prompt = '''
|
||||
あなたは日本酒の専門家(ソムリエ)です。
|
||||
添付の画像(日本酒のラベル)を分析し、以下のJSON形式で情報を抽出してください。
|
||||
|
|
@ -151,7 +151,7 @@ $extractedText
|
|||
}
|
||||
_lastApiCallTime = DateTime.now();
|
||||
|
||||
// 2. 画像をBase64変換 (Phase 4: Images already compressed at capture)
|
||||
// 2. 画像をBase64変換(撮影時に圧縮済み)
|
||||
List<String> base64Images = [];
|
||||
for (final path in imagePaths) {
|
||||
// Read already-compressed images directly (compressed at capture time)
|
||||
|
|
@ -203,7 +203,7 @@ $extractedText
|
|||
|
||||
final result = SakeAnalysisResult.fromJson(data);
|
||||
|
||||
// Phase 3 Validation: Check for Schema Compliance
|
||||
// スキーマ準拠チェック
|
||||
if (result.tasteStats.isEmpty ||
|
||||
result.tasteStats.values.every((v) => v == 0)) {
|
||||
debugPrint('⚠️ WARNING: AI returned empty or zero taste stats. This item will not form a valid chart.');
|
||||
|
|
@ -299,7 +299,7 @@ $extractedText
|
|||
// Prepare Content
|
||||
final contentParts = <Part>[TextPart(promptText)];
|
||||
for (var path in imagePaths) {
|
||||
// Phase 4: Images already compressed at capture time
|
||||
// 撮影時に圧縮済み
|
||||
final bytes = await File(path).readAsBytes();
|
||||
contentParts.add(DataPart('image/jpeg', bytes));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ import 'package:flutter/foundation.dart';
|
|||
|
||||
/// ネットワーク接続状態を管理するサービス
|
||||
///
|
||||
/// Phase 1緊急対応: オフライン対応のための基盤サービス
|
||||
/// - オンライン/オフライン判定
|
||||
/// - 接続状態変化の監視
|
||||
class NetworkService {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import '../screens/pending_analysis_screen.dart';
|
|||
|
||||
/// 未解析Draft(解析待ちアイテム)通知バナー
|
||||
///
|
||||
/// Phase 1: オフライン対応機能の一部
|
||||
/// ホーム画面上部に表示され、未解析のDraftがある場合にのみ表示されます。
|
||||
///
|
||||
/// タップすると [PendingAnalysisScreen] へ遷移し、一括解析が可能です。
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ class _SakeDetailSpecsState extends State<SakeDetailSpecs> {
|
|||
late final TextEditingController _manufacturingController;
|
||||
|
||||
// Unused in UI currently but reserved
|
||||
// TODO: Phase X で甘味度・ボディスコアの編集UIを追加する予定
|
||||
// TODO: 甘味度・ボディスコアの編集UIを追加する予定
|
||||
/*
|
||||
late final TextEditingController _sweetnessController;
|
||||
late final TextEditingController _bodyController;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:lucide_icons/lucide_icons.dart';
|
||||
|
|
@ -72,7 +73,7 @@ class _OtherSettingsSectionState extends ConsumerState<OtherSettingsSection> {
|
|||
leading: Icon(LucideIcons.info, color: appColors.iconDefault),
|
||||
title: Text('アプリバージョン', style: TextStyle(color: appColors.textPrimary)),
|
||||
subtitle: Text(_appVersion, style: TextStyle(color: appColors.textSecondary)),
|
||||
onTap: () {
|
||||
onTap: kReleaseMode ? null : () {
|
||||
setState(() {
|
||||
_devTapCount++;
|
||||
if (_devTapCount >= AppConstants.devModeTapCount) {
|
||||
|
|
@ -83,8 +84,7 @@ class _OtherSettingsSectionState extends ConsumerState<OtherSettingsSection> {
|
|||
MaterialPageRoute(builder: (context) => const DevMenuScreen()),
|
||||
);
|
||||
} else {
|
||||
// Optional: Small feedback
|
||||
HapticFeedback.lightImpact();
|
||||
HapticFeedback.lightImpact();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
|
|
|||
Loading…
Reference in New Issue