import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:habo/habits/habits_manager.dart'; import 'package:habo/navigation/app_state_manager.dart'; import 'package:habo/constants.dart'; class CreateHabitScreen extends StatefulWidget { const CreateHabitScreen({super.key}); @override State createState() => _CreateHabitScreenState(); } class _CreateHabitScreenState extends State { final _titleController = TextEditingController(); final _cueController = TextEditingController(); final _routineController = TextEditingController(); final _rewardController = TextEditingController(); final _sanctionController = TextEditingController(); final _accountantController = TextEditingController(); final _targetValueController = TextEditingController(text: '100'); final _partialValueController = TextEditingController(text: '10'); final _unitController = TextEditingController(); bool _twoDayRule = false; bool _notification = false; bool _advanced = false; bool _habitContract = false; bool _showReward = false; bool _showSanction = false; HabitType _habitType = HabitType.boolean; TimeOfDay _notTime = const TimeOfDay(hour: 20, minute: 0); @override void dispose() { _titleController.dispose(); _cueController.dispose(); _routineController.dispose(); _rewardController.dispose(); _sanctionController.dispose(); _accountantController.dispose(); _targetValueController.dispose(); _partialValueController.dispose(); _unitController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Create Habit'), leading: IconButton( icon: const Icon(Icons.arrow_back), onPressed: () => context.read().goCreateHabit(false), ), actions: [ IconButton( icon: const Icon(Icons.check, color: HaboColors.primary), onPressed: _save, ), ], ), body: ListView( padding: const EdgeInsets.all(16), children: [ // Title TextField( controller: _titleController, autofocus: true, decoration: const InputDecoration( labelText: 'Title *', hintText: 'e.g. Exercise, Reading, Meditation', prefixIcon: Icon(Icons.title), border: OutlineInputBorder(), ), ), const SizedBox(height: 16), // Habit Type Card( child: Padding( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Habit Type', style: Theme.of(context).textTheme.titleSmall?.copyWith( fontWeight: FontWeight.bold, ), ), const SizedBox(height: 8), RadioListTile( title: const Text('Checkable (Yes/No)'), subtitle: const Text('Simple daily check-in'), secondary: const Icon(Icons.check_box), value: HabitType.boolean, groupValue: _habitType, onChanged: (v) => setState(() => _habitType = v!), ), RadioListTile( title: const Text('Progressive (Numeric)'), subtitle: const Text('Track counts like steps, glasses'), secondary: const Icon(Icons.track_changes), value: HabitType.numeric, groupValue: _habitType, onChanged: (v) => setState(() => _habitType = v!), ), ], ), ), ), // Numeric fields if (_habitType == HabitType.numeric) Card( child: Padding( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Progress Settings', style: Theme.of(context).textTheme.titleSmall?.copyWith( fontWeight: FontWeight.bold, ), ), const SizedBox(height: 12), TextField( controller: _targetValueController, keyboardType: const TextInputType.numberWithOptions(decimal: true), decoration: const InputDecoration( labelText: 'Target Value', prefixIcon: Icon(Icons.flag), border: OutlineInputBorder(), ), ), const SizedBox(height: 12), TextField( controller: _partialValueController, keyboardType: const TextInputType.numberWithOptions(decimal: true), decoration: const InputDecoration( labelText: 'Partial Value (increment)', prefixIcon: Icon(Icons.add), border: OutlineInputBorder(), ), ), const SizedBox(height: 12), TextField( controller: _unitController, decoration: const InputDecoration( labelText: 'Unit', hintText: 'e.g. steps, km, glasses', prefixIcon: Icon(Icons.straighten), border: OutlineInputBorder(), ), ), ], ), ), ), // Two Day Rule Card( child: SwitchListTile( title: const Text('Two Day Rule'), subtitle: const Text('Allow one miss without losing streak'), secondary: const Icon(Icons.rule), value: _twoDayRule, onChanged: (v) => setState(() => _twoDayRule = v), ), ), // Notifications Card( child: Column( children: [ SwitchListTile( title: const Text('Daily Reminder'), subtitle: const Text('Get notified to check habits'), secondary: const Icon(Icons.notifications), value: _notification, onChanged: (v) => setState(() => _notification = v), ), if (_notification) Padding( padding: const EdgeInsets.fromLTRB(16, 0, 16, 16), child: OutlinedButton.icon( onPressed: _pickTime, icon: const Icon(Icons.access_time), label: Text('${_notTime.format(context)}'), ), ), ], ), ), // Advanced Options ExpansionTile( leading: const Icon(Icons.tune), title: const Text('Advanced Options'), subtitle: const Text('Cue, Routine, Reward, Habit Contract'), children: [ Padding( padding: const EdgeInsets.all(16), child: Column( children: [ TextField( controller: _cueController, decoration: const InputDecoration( labelText: 'Cue (Trigger)', hintText: 'e.g. At 7:00 AM', prefixIcon: Icon(Icons.flash_on), border: OutlineInputBorder(), ), ), const SizedBox(height: 12), TextField( controller: _routineController, decoration: const InputDecoration( labelText: 'Routine (Action)', hintText: 'e.g. Do 50 push ups', prefixIcon: Icon(Icons.fitness_center), border: OutlineInputBorder(), ), ), const SizedBox(height: 12), Row( children: [ Expanded( child: TextField( controller: _rewardController, decoration: const InputDecoration( labelText: 'Reward', hintText: 'e.g. 15 min games', prefixIcon: Icon(Icons.emoji_events), border: OutlineInputBorder(), ), ), ), const SizedBox(width: 12), Switch(value: _showReward, onChanged: (v) => setState(() => _showReward = v)), ], ), ], ), ), const Divider(), SwitchListTile( title: const Text('Habit Contract'), subtitle: const Text('Set a sanction for missing'), secondary: const Icon(Icons.gavel), value: _habitContract, onChanged: (v) => setState(() => _habitContract = v), ), if (_habitContract) Padding( padding: const EdgeInsets.all(16), child: Column( children: [ TextField( controller: _sanctionController, decoration: const InputDecoration( labelText: 'Sanction', hintText: 'e.g. Donate \$10 to charity', prefixIcon: Icon(Icons.warning), border: OutlineInputBorder(), ), ), const SizedBox(height: 12), TextField( controller: _accountantController, decoration: const InputDecoration( labelText: 'Accountability Partner', hintText: 'e.g. Dan', prefixIcon: Icon(Icons.person), border: OutlineInputBorder(), ), ), ], ), ), ], ), const SizedBox(height: 24), // Save button SizedBox( width: double.infinity, height: 48, child: ElevatedButton.icon( onPressed: _save, icon: const Icon(Icons.check), label: const Text('Save Habit', style: TextStyle(fontSize: 16)), style: ElevatedButton.styleFrom( backgroundColor: HaboColors.primary, foregroundColor: Colors.white, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), ), ), ), const SizedBox(height: 24), ], ), ); } Future _pickTime() async { final picked = await showTimePicker(context: context, initialTime: _notTime); if (picked != null) setState(() => _notTime = picked); } void _save() { if (_titleController.text.trim().isEmpty) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Title cannot be empty!'), backgroundColor: HaboColors.red), ); return; } context.read().addHabit( _titleController.text.trim(), _twoDayRule, _cueController.text, _routineController.text, _rewardController.text, _showReward, _advanced || _habitContract, _notification, _notTime, _sanctionController.text, _showSanction, _accountantController.text, habitType: _habitType, targetValue: double.tryParse(_targetValueController.text) ?? 100.0, partialValue: double.tryParse(_partialValueController.text) ?? 10.0, unit: _unitController.text, ); context.read().goCreateHabit(false); } }