Compare commits

...

5 Commits

Author SHA1 Message Date
Ponshu Developer 5dde69788b chore: update releases.json to v1.0.18
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 07:34:16 +09:00
Ponshu Developer 4eaa292b02 chore: bump version to 1.0.18+29
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 07:30:33 +09:00
Ponshu Developer d61427d7f6 feat: add grid text toggle to display settings (promoted from DevMenu)
一覧テキスト表示のON/OFFをSoulScreenの表示設定から操作可能に。
DevMenuのままだった機能を正式設定として昇格。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 07:26:42 +09:00
Ponshu Developer b6163e8efe 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>
2026-04-05 03:02:01 +09:00
Ponshu Developer 426697403e fix: add maxLines/overflow to MBTI subtitle in soul_screen
長いMBTIタイトルがListTile内でUI崩れを起こす可能性があったため対処。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 02:51:42 +09:00
20 changed files with 43 additions and 38 deletions

View File

@ -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,
);

View File

@ -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;

View File

@ -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.

View File

@ -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

View File

@ -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');

View File

@ -21,9 +21,6 @@ class DevMenuScreen extends ConsumerWidget {
),
body: ListView(
children: [
// NOTE: (SoulScreen)
// UI実験
const ListTile(
leading: Icon(LucideIcons.flaskConical),
title: Text('UI実験'),

View File

@ -143,7 +143,7 @@ class HomeScreen extends ConsumerWidget {
body: SafeArea(
child: Column(
children: [
// Phase 1: Draft通知バナー
// Draft通知バナー
const PendingAnalysisBanner(),
if (!isMenuMode && hasItems)

View File

@ -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);

View File

@ -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,

View File

@ -104,7 +104,9 @@ class _SoulScreenState extends ConsumerState<SoulScreen> {
userProfile.sakePersonaMbti != null
? MBTIType.types[userProfile.sakePersonaMbti]?.title ?? userProfile.sakePersonaMbti!
: '未診断AI分析',
style: TextStyle(color: appColors.textSecondary)
style: TextStyle(color: appColors.textSecondary),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
trailing: Icon(LucideIcons.chevronRight, color: appColors.iconSubtle),
onTap: () {

View File

@ -128,9 +128,7 @@ class AnalysisCacheService {
/// - 30
/// -
static Future<void> cleanupExpired() async {
// TODO: Phase 3
// -
// - 30
// TODO: 30
}
// ============================================

View File

@ -6,7 +6,7 @@ import 'gemini_service.dart';
/// Draft
///
/// Phase 1:
///
///
///
/// 使:

View File

@ -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));
}

View File

@ -3,7 +3,6 @@ import 'package:flutter/foundation.dart';
///
///
/// Phase 1:
/// - /
/// -
class NetworkService {

View File

@ -6,7 +6,6 @@ import '../screens/pending_analysis_screen.dart';
/// Draft
///
/// Phase 1:
/// Draftがある場合にのみ表示されます
///
/// [PendingAnalysisScreen]

View File

@ -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;

View File

@ -66,6 +66,16 @@ class DisplaySettingsSection extends ConsumerWidget {
trailing: Icon(LucideIcons.chevronRight, color: appColors.iconSubtle),
onTap: () => _showThemeDialog(context, ref, themeMode),
),
Divider(height: 1, color: appColors.divider),
// 5.
SwitchListTile(
secondary: Icon(LucideIcons.textCursorInput, color: appColors.iconDefault),
title: Text('一覧にテキストを表示', style: TextStyle(color: appColors.textPrimary)),
subtitle: Text('写真上に銘柄名・蔵元を重ねて表示', style: TextStyle(color: appColors.textSecondary)),
value: experiment.showGridText,
onChanged: (val) => ref.read(uiExperimentProvider.notifier).setShowGridText(val),
),
],
),
),

View File

@ -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();
}
});
},

View File

@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix.
version: 1.0.17+28
version: 1.0.18+29
environment:
sdk: ^3.10.1

View File

@ -1,18 +1,18 @@
{
"date": "2026-04-04",
"name": "Ponshu Room 1.0.17 (2026-04-04)",
"version": "v1.0.17",
"date": "2026-04-05",
"name": "Ponshu Room 1.0.18 (2026-04-05)",
"version": "v1.0.18",
"apks": {
"eiji": {
"lite": {
"url": "https://posimai-lab.tail72e846.ts.net/mai/ponshu-room-lite/releases/download/v1.0.17/ponshu_room_consumer_eiji.apk",
"url": "https://posimai-lab.tail72e846.ts.net/mai/ponshu-room-lite/releases/download/v1.0.18/ponshu_room_consumer_eiji.apk",
"size_mb": 89,
"filename": "ponshu_room_consumer_eiji.apk"
}
},
"maita": {
"lite": {
"url": "https://posimai-lab.tail72e846.ts.net/mai/ponshu-room-lite/releases/download/v1.0.17/ponshu_room_consumer_maita.apk",
"url": "https://posimai-lab.tail72e846.ts.net/mai/ponshu-room-lite/releases/download/v1.0.18/ponshu_room_consumer_maita.apk",
"size_mb": 89,
"filename": "ponshu_room_consumer_maita.apk"
}