import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:intl/intl.dart'; import 'package:flutter/cupertino.dart'; // For Rolling Picker import 'pdf_preview_screen.dart'; import 'package:hive_flutter/hive_flutter.dart'; import '../providers/menu_providers.dart'; import '../models/sake_item.dart'; import '../models/menu_settings.dart'; import '../providers/sake_list_provider.dart'; import '../widgets/step_indicator.dart'; import '../theme/app_theme.dart'; class MenuSettingsScreen extends ConsumerStatefulWidget { const MenuSettingsScreen({super.key}); @override ConsumerState createState() => _MenuSettingsScreenState(); } class _MenuSettingsScreenState extends ConsumerState { // Display options bool includePhoto = true; bool includePoem = true; bool includeChart = true; bool includePrice = true; bool includeDate = true; bool includeQr = false; // Default false for QR // PDF settings String pdfSize = 'a4'; // 'a4', 'a5', 'b5' bool isMonochrome = false; // TextEditingControllers late final TextEditingController _titleController; late final TextEditingController _dateController; // Stores date string @override void initState() { super.initState(); _loadSettings(); } // Load saved settings from Hive void _loadSettings() { final box = Hive.box('menu_settings'); final savedSettings = box.get('current', defaultValue: MenuSettings()); // Initialize controllers first to avoid null reference errors _titleController = TextEditingController(); _dateController = TextEditingController( text: DateFormat('yyyy年M月d日').format(DateTime.now()), ); if (savedSettings != null) { setState(() { includePhoto = savedSettings.includePhoto; includePoem = savedSettings.includePoem; includeChart = savedSettings.includeChart; includePrice = savedSettings.includePrice; includeDate = savedSettings.includeDate; includeQr = savedSettings.includeQr ?? false; // Handle migration safely if null pdfSize = savedSettings.pdfSize; isMonochrome = savedSettings.isMonochrome; }); // Update controller text if saved settings exist _titleController.text = savedSettings.title; } } // Save settings to Hive Future _saveSettings() async { final box = Hive.box('menu_settings'); final settings = MenuSettings( title: _titleController.text, includePhoto: includePhoto, includePoem: includePoem, includeChart: includeChart, includePrice: includePrice, includeDate: includeDate, includeQr: includeQr, pdfSize: pdfSize, isMonochrome: isMonochrome, ); await box.put('current', settings); } @override void dispose() { _titleController.dispose(); _dateController.dispose(); super.dispose(); } Future _showRollingDatePicker() async { DateTime initialDate = DateTime.now(); try { // Try parsing current text, fallback to now final format = DateFormat('yyyy年M月d日'); initialDate = format.parse(_dateController.text); } catch (_) {} await showCupertinoModalPopup( context: context, builder: (BuildContext context) => Container( height: 216, padding: const EdgeInsets.only(top: 6.0), margin: EdgeInsets.only( bottom: MediaQuery.of(context).viewInsets.bottom, ), color: CupertinoColors.systemBackground.resolveFrom(context), child: SafeArea( top: false, child: CupertinoDatePicker( initialDateTime: initialDate, mode: CupertinoDatePickerMode.date, use24hFormat: true, // Japanese locale logic if needed, but standard picker usually sufficient onDateTimeChanged: (DateTime newDate) { setState(() { _dateController.text = DateFormat('yyyy年M月d日').format(newDate); }); _saveSettings(); }, ), ), ), ); } @override Widget build(BuildContext context) { // Determine selected items and order final selectedIds = ref.watch(selectedMenuSakeIdsProvider); final orderedIds = ref.watch(menuOrderedIdsProvider); final sakeListAsync = ref.watch(sakeListProvider); final selectedItems = sakeListAsync.when( data: (list) { if (orderedIds.isNotEmpty) { final sakeMap = {for (var s in list) s.id: s}; return orderedIds .map((id) => sakeMap[id]) .whereType() .where((s) => selectedIds.contains(s.id)) .toList(); } else { return list.where((item) => selectedIds.contains(item.id)).toList(); } }, loading: () => [], error: (_, __) => [], ); return Scaffold( appBar: AppBar( automaticallyImplyLeading: false, title: const StepIndicator(currentStep: 3, totalSteps: 3), centerTitle: true, actions: [ IconButton( icon: const Icon(Icons.close), tooltip: '終了', onPressed: () => _showExitDialog(context, ref), ), ], bottom: PreferredSize( preferredSize: const Size.fromHeight(2), child: LinearProgressIndicator( value: 1.0, // Step 3 of 3 = 100% backgroundColor: Colors.grey[200], valueColor: const AlwaysStoppedAnimation(AppTheme.posimaiBlue), minHeight: 2, ), ), ), body: selectedItems.isEmpty ? const Center(child: Text('お酒が選択されていません')) : Column( children: [ Expanded( child: ListView( padding: const EdgeInsets.all(16), children: [ // Preview List (Simple) Text( '選択中: ${selectedItems.length}銘柄', style: Theme.of(context).textTheme.titleMedium, ), const Divider(), ...selectedItems.map((sake) => ListTile( leading: const Icon(Icons.check, size: 16), title: Text(sake.displayData.name), subtitle: Text('${sake.displayData.brewery} / ${sake.displayData.prefecture}'), dense: true, )), const Divider(height: 32), // Menu Attributes Text( 'お品書き情報', style: Theme.of(context).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.bold), ), const SizedBox(height: 8), TextField( controller: _titleController, decoration: const InputDecoration( labelText: 'タイトル', hintText: '日本酒リスト', border: OutlineInputBorder(), ), onChanged: (value) => _saveSettings(), ), const SizedBox(height: 24), // Display Toggles with SwitchListTile Text( '表示項目', style: Theme.of(context).textTheme.titleMedium?.copyWith( fontWeight: FontWeight.bold, color: AppTheme.posimaiBlue, ), ), const SizedBox(height: 8), Card( elevation: 0, color: Theme.of(context).colorScheme.surfaceContainerHighest.withValues(alpha: 0.3), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), child: Column( children: [ SwitchListTile( title: const Text('写真'), value: includePhoto, onChanged: (val) => setState(() { includePhoto = val; _saveSettings(); }), ), const Divider(height: 1), SwitchListTile( title: const Text('キャッチコピー / 説明文'), value: includePoem, onChanged: (val) => setState(() { includePoem = val; _saveSettings(); }), ), const Divider(height: 1), SwitchListTile( title: const Text('価格'), value: includePrice, onChanged: (val) => setState(() { includePrice = val; _saveSettings(); }), ), const Divider(height: 1), // QR Toggle SwitchListTile( title: const Text('QRコード(銘柄情報表示)'), subtitle: const Text('ぽんるーむアプリでスキャンすると銘柄情報を表示', style: TextStyle(fontSize: 10, color: Colors.grey)), value: includeQr, onChanged: (val) => setState(() { includeQr = val; _saveSettings(); }), ), const Divider(height: 1), // Date Toggle in List SwitchListTile( title: const Text('日付'), value: includeDate, onChanged: (val) => setState(() { includeDate = val; _saveSettings(); }), ), if (includeDate) ...[ const Divider(height: 1), ListTile( leading: const Icon(Icons.calendar_today, size: 20), title: Text(_dateController.text), trailing: const Icon(Icons.arrow_forward_ios, size: 16), onTap: _showRollingDatePicker, dense: true, ), ], ], ), ), const SizedBox(height: 24), // PDF Settings (Restored) Text( 'PDF設定', style: Theme.of(context).textTheme.titleMedium?.copyWith( fontWeight: FontWeight.bold, color: AppTheme.posimaiBlue, ), ), const SizedBox(height: 8), // Paper Size Selection Text( '用紙サイズ', style: Theme.of(context).textTheme.bodyMedium?.copyWith(fontWeight: FontWeight.bold), ), const SizedBox(height: 8), Row( children: [ _buildPaperSizeCard('a5', 'A5', '148 × 210 mm'), const SizedBox(width: 12), _buildPaperSizeCard('b5', 'B5', '182 × 257 mm'), const SizedBox(width: 12), _buildPaperSizeCard('a4', 'A4', '210 × 297 mm'), ], ), const SizedBox(height: 16), // Orientation Toggle (Custom Layout) Padding( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text('縦向き', style: TextStyle(fontWeight: FontWeight.bold)), Switch( value: ref.watch(pdfIsPortraitProvider), activeThumbColor: AppTheme.posimaiBlue, onChanged: (val) => ref.read(pdfIsPortraitProvider.notifier).set(val), ), ], ), ), const Divider(height: 1), // Density Slider (Pro Feature) Padding( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ const Text('銘柄の間隔', style: TextStyle(fontWeight: FontWeight.bold)), Text( '${(ref.watch(pdfDensityProvider) * 100).round()}%', style: TextStyle(fontWeight: FontWeight.bold, color: AppTheme.posimaiBlue), ), ], ), const SizedBox(height: 4), Text( '数値を上げると1枚に多く入ります', style: Theme.of(context).textTheme.bodySmall?.copyWith(color: Colors.grey), ), Slider( value: ref.watch(pdfDensityProvider).clamp(1.0, 2.0), min: 1.0, max: 2.0, divisions: 10, label: '${(ref.watch(pdfDensityProvider) * 100).round()}%', activeColor: AppTheme.posimaiBlue, onChanged: (val) { ref.read(pdfDensityProvider.notifier).set(val); }, ), ], ), ), const Divider(height: 1), // Color/Monochrome Toggle (Custom Layout) Padding( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ const Text('カラー', style: TextStyle(fontWeight: FontWeight.bold)), Switch( value: !isMonochrome, // ON = Color (!Monochrome) activeThumbColor: AppTheme.posimaiBlue, onChanged: (val) => setState(() { isMonochrome = !val; // Toggle logic ref.read(pdfIsMonochromeProvider.notifier).set(isMonochrome); _saveSettings(); }), ), ], ), ), ], ), ), SafeArea( child: Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Theme.of(context).cardColor, boxShadow: [ BoxShadow( color: Colors.black.withValues(alpha: 0.05), blurRadius: 8, offset: const Offset(0, -2), ), ], ), child: Row( children: [ // 戻るボタン (左端) SizedBox( width: 56, height: 56, child: OutlinedButton( onPressed: () => Navigator.pop(context), style: OutlinedButton.styleFrom( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), side: BorderSide(color: Colors.grey[300]!), padding: EdgeInsets.zero, ), child: Icon(Icons.arrow_back, color: Colors.grey[700]), ), ), const SizedBox(width: 12), // プレビューボタン (右側いっぱいに広がる) Expanded( child: SizedBox( height: 56, child: ElevatedButton.icon( onPressed: () { Navigator.of(context).push( MaterialPageRoute( builder: (context) => PdfPreviewScreen( items: selectedItems, title: _titleController.text, date: _dateController.text, includePhoto: includePhoto, includePoem: includePoem, includeChart: includeChart, includePrice: includePrice, includeDate: includeDate, includeQr: includeQr, // New Argument pdfSize: pdfSize, isMonochrome: isMonochrome, ), ), ); }, style: ElevatedButton.styleFrom( backgroundColor: AppTheme.posimaiBlue, foregroundColor: Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), ), icon: const Icon(Icons.picture_as_pdf), label: const Text('プレビュー', style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)), ), ), ), ], ), ), ), ], ), ); } Future _showExitDialog(BuildContext context, WidgetRef ref) async { final confirmed = await showDialog( context: context, builder: (context) => AlertDialog( title: const Text('お品書き作成を終了しますか?'), content: const Text('入力内容は保存されません。'), actions: [ TextButton( child: const Text('キャンセル'), onPressed: () => Navigator.pop(context, false), ), ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: AppTheme.posimaiBlue, foregroundColor: Colors.white, ), onPressed: () => Navigator.pop(context, true), child: const Text('終了'), ), ], ), ); if (confirmed == true && context.mounted) { ref.read(menuModeProvider.notifier).set(false); ref.read(selectedMenuSakeIdsProvider.notifier).clear(); Navigator.of(context).popUntil((route) => route.isFirst); } } Widget _buildPaperSizeCard(String value, String label, String sublabel) { final isSelected = pdfSize == value; final colorScheme = Theme.of(context).colorScheme; return Expanded( child: GestureDetector( onTap: () { setState(() { pdfSize = value; _saveSettings(); }); }, child: Container( padding: const EdgeInsets.symmetric(vertical: 16), decoration: BoxDecoration( color: isSelected ? colorScheme.primaryContainer.withValues(alpha: 0.2) : colorScheme.surfaceContainerHighest, borderRadius: BorderRadius.circular(12), border: Border.all( color: isSelected ? colorScheme.primary : Colors.transparent, width: 2, ), ), child: Column( children: [ Icon( isSelected ? Icons.check_box : Icons.crop_portrait, // Use crop_portrait as generic paper icon color: isSelected ? colorScheme.primary : colorScheme.onSurfaceVariant, ), const SizedBox(height: 8), Text( label, style: TextStyle( fontWeight: FontWeight.bold, color: isSelected ? colorScheme.primary : colorScheme.onSurface, ), ), Text( sublabel, style: TextStyle( fontSize: 10, color: colorScheme.onSurfaceVariant, ), ), ], ), ), ), ); } }