Implement Notifications and Pad Tracking Enhancements
This commit is contained in:
@@ -23,7 +23,7 @@ class _QuickLogDialogState extends ConsumerState<QuickLogDialog> {
|
||||
FlowIntensity? _flowIntensity;
|
||||
MoodLevel? _mood;
|
||||
int? _energyLevel;
|
||||
|
||||
|
||||
// Symptoms & Cravings
|
||||
final Map<String, bool> _symptoms = {
|
||||
'Headache': false,
|
||||
@@ -37,7 +37,7 @@ class _QuickLogDialogState extends ConsumerState<QuickLogDialog> {
|
||||
'Insomnia': false,
|
||||
'Cramps': false,
|
||||
};
|
||||
|
||||
|
||||
final TextEditingController _cravingController = TextEditingController();
|
||||
List<String> _cravings = [];
|
||||
List<String> _recentCravings = [];
|
||||
@@ -102,6 +102,8 @@ class _QuickLogDialogState extends ConsumerState<QuickLogDialog> {
|
||||
return _buildSymptomsLog();
|
||||
case 'cravings':
|
||||
return _buildCravingsLog();
|
||||
case 'prayer':
|
||||
return _buildPrayerLog();
|
||||
default:
|
||||
return const Text('Invalid log type.');
|
||||
}
|
||||
@@ -137,7 +139,7 @@ class _QuickLogDialogState extends ConsumerState<QuickLogDialog> {
|
||||
}
|
||||
|
||||
Widget _buildCravingsLog() {
|
||||
return Container(
|
||||
return Container(
|
||||
width: double.maxFinite,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
@@ -152,37 +154,44 @@ class _QuickLogDialogState extends ConsumerState<QuickLogDialog> {
|
||||
),
|
||||
onSubmitted: (value) {
|
||||
if (value.isNotEmpty) {
|
||||
setState(() {
|
||||
_cravings.add(value.trim());
|
||||
_cravingController.clear();
|
||||
});
|
||||
setState(() {
|
||||
_cravings.add(value.trim());
|
||||
_cravingController.clear();
|
||||
});
|
||||
}
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Wrap(
|
||||
spacing: 8,
|
||||
children: _cravings.map((c) => Chip(
|
||||
label: Text(c),
|
||||
onDeleted: () {
|
||||
setState(() => _cravings.remove(c));
|
||||
},
|
||||
)).toList(),
|
||||
children: _cravings
|
||||
.map((c) => Chip(
|
||||
label: Text(c),
|
||||
onDeleted: () {
|
||||
setState(() => _cravings.remove(c));
|
||||
},
|
||||
))
|
||||
.toList(),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
if (_recentCravings.isNotEmpty) ...[
|
||||
Text('Recent Cravings:', style: GoogleFonts.outfit(fontSize: 12, fontWeight: FontWeight.bold)),
|
||||
Text('Recent Cravings:',
|
||||
style: GoogleFonts.outfit(
|
||||
fontSize: 12, fontWeight: FontWeight.bold)),
|
||||
const SizedBox(height: 8),
|
||||
Wrap(
|
||||
Wrap(
|
||||
spacing: 8,
|
||||
children: _recentCravings.take(5).map((c) => ActionChip(
|
||||
label: Text(c),
|
||||
onPressed: () {
|
||||
if (!_cravings.contains(c)) {
|
||||
setState(() => _cravings.add(c));
|
||||
}
|
||||
},
|
||||
)).toList(),
|
||||
children: _recentCravings
|
||||
.take(5)
|
||||
.map((c) => ActionChip(
|
||||
label: Text(c),
|
||||
onPressed: () {
|
||||
if (!_cravings.contains(c)) {
|
||||
setState(() => _cravings.add(c));
|
||||
}
|
||||
},
|
||||
))
|
||||
.toList(),
|
||||
),
|
||||
]
|
||||
],
|
||||
@@ -277,10 +286,30 @@ class _QuickLogDialogState extends ConsumerState<QuickLogDialog> {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildPrayerLog() {
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text('Enter your prayer request or gratitude:'),
|
||||
const SizedBox(height: 16),
|
||||
TextField(
|
||||
controller:
|
||||
_cravingController, // Reusing controller for simplicity, or create _prayerController
|
||||
maxLines: 4,
|
||||
decoration: const InputDecoration(
|
||||
hintText: 'I am thankful for...',
|
||||
border: OutlineInputBorder(),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _saveLog() async {
|
||||
// Handle text input for cravings if user didn't hit enter
|
||||
if (widget.logType == 'cravings' && _cravingController.text.isNotEmpty) {
|
||||
_cravings.add(_cravingController.text.trim());
|
||||
_cravings.add(_cravingController.text.trim());
|
||||
}
|
||||
|
||||
final cycleNotifier = ref.read(cycleEntriesProvider.notifier);
|
||||
@@ -288,7 +317,11 @@ class _QuickLogDialogState extends ConsumerState<QuickLogDialog> {
|
||||
final entries = ref.read(cycleEntriesProvider);
|
||||
final entry = entries.firstWhere(
|
||||
(e) => DateUtils.isSameDay(e.date, today),
|
||||
orElse: () => CycleEntry(id: const Uuid().v4(), date: today, createdAt: today, updatedAt: today),
|
||||
orElse: () => CycleEntry(
|
||||
id: const Uuid().v4(),
|
||||
date: today,
|
||||
createdAt: today,
|
||||
updatedAt: today),
|
||||
);
|
||||
|
||||
CycleEntry updatedEntry = entry;
|
||||
@@ -308,28 +341,61 @@ class _QuickLogDialogState extends ConsumerState<QuickLogDialog> {
|
||||
break;
|
||||
case 'symptoms':
|
||||
updatedEntry = entry.copyWith(
|
||||
hasHeadache: _symptoms['Headache'],
|
||||
hasBloating: _symptoms['Bloating'],
|
||||
hasBreastTenderness: _symptoms['Breast Tenderness'],
|
||||
hasFatigue: _symptoms['Fatigue'],
|
||||
hasAcne: _symptoms['Acne'],
|
||||
hasLowerBackPain: _symptoms['Back Pain'],
|
||||
hasConstipation: _symptoms['Constipation'],
|
||||
hasDiarrhea: _symptoms['Diarrhea'],
|
||||
hasInsomnia: _symptoms['Insomnia'],
|
||||
crampIntensity: _symptoms['Cramps'] == true ? 2 : 0, // Default to mild cramps if just toggled
|
||||
hasHeadache: _symptoms['Headache'],
|
||||
hasBloating: _symptoms['Bloating'],
|
||||
hasBreastTenderness: _symptoms['Breast Tenderness'],
|
||||
hasFatigue: _symptoms['Fatigue'],
|
||||
hasAcne: _symptoms['Acne'],
|
||||
hasLowerBackPain: _symptoms['Back Pain'],
|
||||
hasConstipation: _symptoms['Constipation'],
|
||||
hasDiarrhea: _symptoms['Diarrhea'],
|
||||
hasInsomnia: _symptoms['Insomnia'],
|
||||
crampIntensity: _symptoms['Cramps'] == true
|
||||
? 2
|
||||
: 0, // Default to mild cramps if just toggled
|
||||
);
|
||||
// Trigger notification if any symptom is selected
|
||||
final user = ref.read(userProfileProvider);
|
||||
if (_symptoms.values.any((selected) => selected == true)) {
|
||||
final selectedSymptom = _symptoms.entries
|
||||
.firstWhere((element) => element.value == true)
|
||||
.key;
|
||||
NotificationService().showSymptomNotification(
|
||||
senderName: user?.name ?? 'Wife',
|
||||
symptom: selectedSymptom,
|
||||
);
|
||||
}
|
||||
break;
|
||||
case 'cravings':
|
||||
final currentCravings = entry.cravings ?? [];
|
||||
final newCravings = {...currentCravings, ..._cravings}.toList();
|
||||
updatedEntry = entry.copyWith(cravings: newCravings);
|
||||
|
||||
|
||||
// Update History
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
final history = prefs.getStringList('recent_cravings') ?? [];
|
||||
final updatedHistory = {..._cravings, ...history}.take(20).toList();
|
||||
await prefs.setStringList('recent_cravings', updatedHistory);
|
||||
await prefs.setStringList('recent_cravings', updatedHistory);
|
||||
break;
|
||||
case 'prayer':
|
||||
final currentPrayer = entry.prayerRequest ?? '';
|
||||
final newPrayer =
|
||||
_cravingController.text.trim(); // Using reused controller
|
||||
if (newPrayer.isNotEmpty) {
|
||||
updatedEntry = entry.copyWith(
|
||||
prayerRequest: currentPrayer.isEmpty
|
||||
? newPrayer
|
||||
: '$currentPrayer\n$newPrayer');
|
||||
|
||||
// Trigger notification
|
||||
final user = ref.read(userProfileProvider);
|
||||
NotificationService().showPrayerRequestNotification(
|
||||
senderName: user?.name ?? 'Wife',
|
||||
);
|
||||
} else {
|
||||
return; // Don't save empty prayer
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// pads handled separately
|
||||
|
||||
Reference in New Issue
Block a user