first commit - migrated from codeberg

This commit is contained in:
Charlotte Croce 2025-04-20 11:17:03 -04:00
commit 5ead03e1f7
567 changed files with 102721 additions and 0 deletions

View file

@ -0,0 +1,383 @@
// SPDX-FileCopyrightText: © 2025 Nøkken.io <nokken.io@proton.me>
// SPDX-License-Identifier: AGPL-3.0
//
// bloodwork_data_generator.dart
//
import 'dart:math' show Random;
import 'package:flutter/material.dart';
import 'package:nokken/src/core/services/database/database_service.dart';
import 'package:nokken/src/features/bloodwork_tracker/models/bloodwork.dart';
/// A tool class to generate historical bloodwork data
class BloodworkDataGenerator {
final DatabaseService databaseService;
BloodworkDataGenerator(this.databaseService);
/// Generate bloodwork data, including:
/// - Bloodwork labs every 70-110 days
/// - 2-4 doctor appointments throughout the year
/// - 1 surgery appointment
Future<void> generateBloodworkData() async {
final random = Random();
// Start date: 364 days ago from today
final endDate = DateTime.now();
final startDate = endDate.subtract(const Duration(days: 364));
debugPrint(
'Generating bloodwork data from ${startDate.toIso8601String()} to ${endDate.toIso8601String()}');
// Generate bloodwork labs
await _generateBloodworkLabs(startDate, endDate, random);
// Generate doctor appointments
await _generateDoctorAppointments(startDate, endDate, random);
// Generate a surgery appointment
await _generateSurgeryAppointment(startDate, endDate, random);
debugPrint('Successfully generated bloodwork data.');
}
/// Generate bloodwork labs every 70-110 days
Future<void> _generateBloodworkLabs(
DateTime startDate, DateTime endDate, Random random) async {
// Start a bit before the actual start date to ensure we have consistent coverage
DateTime currentDate = startDate.subtract(const Duration(days: 30));
int labCount = 0;
while (currentDate.isBefore(endDate)) {
// Add a random interval between 70-110 days
final interval = random.nextInt(41) + 70; // 70-110 days
currentDate = currentDate.add(Duration(days: interval));
// Only add if it's within our target range
if (currentDate.isAfter(startDate) && currentDate.isBefore(endDate)) {
// Generate a bloodwork entry
final bloodwork = _generateBloodworkEntry(currentDate, random);
await databaseService.insertBloodwork(bloodwork);
labCount++;
}
}
debugPrint('Generated $labCount bloodwork lab records');
}
/// Generate 2-4 doctor appointments throughout the year
Future<void> _generateDoctorAppointments(
DateTime startDate, DateTime endDate, Random random) async {
// Decide how many appointments (2-4)
final appointmentCount = random.nextInt(3) + 2; // 2-4
debugPrint('Generating $appointmentCount doctor appointments');
// Generate appointment dates (evenly spaced with some randomness)
final yearInDays = 364;
final appointmentDates = <DateTime>[];
for (int i = 0; i < appointmentCount; i++) {
// Calculate roughly evenly spaced dates with some randomness
final targetDay = ((i + 1) * yearInDays / (appointmentCount + 1)).round();
final randomOffset = random.nextInt(21) - 10; // +/- 10 days
final dayOffset = targetDay + randomOffset;
final appointmentDate = startDate.add(Duration(days: dayOffset));
appointmentDates.add(appointmentDate);
}
// Sort dates and ensure no duplicates
appointmentDates.sort((a, b) => a.compareTo(b));
final uniqueDates = <DateTime>[];
DateTime? lastDate;
for (final date in appointmentDates) {
if (lastDate == null || date.difference(lastDate).inDays > 30) {
// Ensure at least 30 days between appointments
uniqueDates.add(date);
lastDate = date;
}
}
// Create and insert appointment records
for (final date in uniqueDates) {
final appointment = _generateAppointmentEntry(date, random);
await databaseService.insertBloodwork(appointment);
}
debugPrint('Generated ${uniqueDates.length} doctor appointment records');
}
/// Generate a surgery appointment within the year
Future<void> _generateSurgeryAppointment(
DateTime startDate, DateTime endDate, Random random) async {
// Place surgery in the middle third of the year (not too recent, not too far back)
final yearInDays = 364;
final targetDayStart = yearInDays ~/ 3;
final targetDayEnd = (yearInDays * 2) ~/ 3;
final dayOffset =
random.nextInt(targetDayEnd - targetDayStart) + targetDayStart;
final surgeryDate = startDate.add(Duration(days: dayOffset));
final surgery = _generateSurgeryEntry(surgeryDate, random);
await databaseService.insertBloodwork(surgery);
debugPrint('Generated surgery record for ${surgeryDate.toIso8601String()}');
}
/// Generate a bloodwork lab entry
Bloodwork _generateBloodworkEntry(DateTime date, Random random) {
// Always include the four required hormones
final hormoneReadings = <HormoneReading>[
_generateHormoneReading('Estradiol', random),
_generateHormoneReading('Testosterone', random),
_generateHormoneReading('Progesterone', random),
_generateHormoneReading('Prolactin', random),
];
// Add 0-6 additional random hormones
final additionalCount = random.nextInt(7); // 0-6
final allHormoneTypes = HormoneTypes.getHormoneTypes();
final requiredTypes = {
'Estradiol',
'Testosterone',
'Progesterone',
'Prolactin'
};
final availableTypes =
allHormoneTypes.where((type) => !requiredTypes.contains(type)).toList();
// Shuffle and take random selection
availableTypes.shuffle(random);
for (int i = 0; i < additionalCount && i < availableTypes.length; i++) {
hormoneReadings.add(_generateHormoneReading(availableTypes[i], random));
}
// Random time
final timeHour = random.nextInt(8) + 8; // Between a8am and 4pm
final timeMinute = random.nextInt(4) * 15; // 0, 15, 30, or 45 minutes
final dateTime = DateTime(
date.year,
date.month,
date.day,
timeHour,
timeMinute,
);
// Random location
final locations = [
'Main Hospital Lab',
'Downtown Clinic',
'Westside Medical Center',
'University Health Services',
'Eastside Lab',
];
final location = locations[random.nextInt(locations.length)];
// Random doctor
final doctors = [
'Dr. Martinez',
'Dr. Johnson',
'Dr. Williams',
'Dr. Chen',
'Dr. Taylor',
];
final doctor = doctors[random.nextInt(doctors.length)];
// Random notes
final notesOptions = [
'Routine bloodwork',
'Follow-up lab work',
'Quarterly hormone check',
'Regular monitoring',
'Medication adjustment labs',
null, // Sometimes no notes
];
final notes = notesOptions[random.nextInt(notesOptions.length)];
return Bloodwork(
date: dateTime,
appointmentType: AppointmentType.bloodwork,
hormoneReadings: hormoneReadings,
location: location,
doctor: doctor,
notes: notes,
);
}
/// Generate a doctor appointment entry
Bloodwork _generateAppointmentEntry(DateTime date, Random random) {
// Random time
final timeHour = random.nextInt(8) + 9; // Between 9am and 5pm
final timeMinute = random.nextInt(4) * 15; // 0, 15, 30, or 45 minutes
final dateTime = DateTime(
date.year,
date.month,
date.day,
timeHour,
timeMinute,
);
// Random location
final locations = [
'Primary Care Clinic',
'Endocrinology Department',
'Specialty Clinic',
'Medical Center',
'Healthcare Associates',
];
final location = locations[random.nextInt(locations.length)];
// Random doctor
final doctors = [
'Dr. Martinez',
'Dr. Johnson',
'Dr. Williams',
'Dr. Chen',
'Dr. Taylor',
];
final doctor = doctors[random.nextInt(doctors.length)];
// Random notes
final notesOptions = [
'Regular checkup',
'Follow-up appointment',
'Medication review',
'Consultation',
'Care planning',
'Treatment discussion',
null, // Sometimes no notes
];
final notes = notesOptions[random.nextInt(notesOptions.length)];
return Bloodwork(
date: dateTime,
appointmentType: AppointmentType.appointment,
hormoneReadings: [], // No hormone readings for appointments
location: location,
doctor: doctor,
notes: notes,
);
}
/// Generate a surgery entry
Bloodwork _generateSurgeryEntry(DateTime date, Random random) {
// Random time (surgeries often early)
final timeHour = random.nextInt(5) + 7; // Between 7am and 12pm
final timeMinute = random.nextInt(4) * 15; // 0, 15, 30, or 45 minutes
final dateTime = DateTime(
date.year,
date.month,
date.day,
timeHour,
timeMinute,
);
// Random location
final locations = [
'University Hospital',
'Memorial Surgery Center',
'Medical Center',
'Surgical Institute',
'Regional Hospital',
];
final location = locations[random.nextInt(locations.length)];
// Random doctor
final doctors = [
'Dr. Garcia',
'Dr. Smith',
'Dr. Patel',
'Dr. Wilson',
'Dr. Lee',
];
final doctor = doctors[random.nextInt(doctors.length)];
// Random notes about the surgery
final notesOptions = [
'Scheduled procedure',
'Outpatient surgery',
'Routine operation',
'Elective procedure',
'Standard intervention',
];
final notes = notesOptions[random.nextInt(notesOptions.length)];
return Bloodwork(
date: dateTime,
appointmentType: AppointmentType.surgery,
hormoneReadings: [], // No hormone readings for surgery
location: location,
doctor: doctor,
notes: notes,
);
}
/// Generate a random hormone reading
HormoneReading _generateHormoneReading(String hormoneName, Random random) {
// Get the default unit for this hormone
final unit = HormoneTypes.getDefaultUnit(hormoneName);
// Generate a reasonable value based on the hormone type
double value;
switch (hormoneName) {
case 'Estradiol':
// Typical range: 30-400 pg/mL
value = 30.0 + random.nextDouble() * 370.0;
break;
case 'Testosterone':
// Typical range: 15-70 ng/dL for women, 300-1000 ng/dL for men
value = 15.0 + random.nextDouble() * 500.0;
break;
case 'Progesterone':
// Typical range: 0.1-25 ng/mL
value = 0.1 + random.nextDouble() * 24.9;
break;
case 'Prolactin':
// Typical range: 3-30 ng/mL
value = 3.0 + random.nextDouble() * 27.0;
break;
case 'FSH':
// Typical range: 4-25 mIU/mL
value = 4.0 + random.nextDouble() * 21.0;
break;
case 'LH':
// Typical range: 2-20 mIU/mL
value = 2.0 + random.nextDouble() * 18.0;
break;
case 'TSH':
// Typical range: 0.4-4.0 μIU/mL
value = 0.4 + random.nextDouble() * 3.6;
break;
case 'Free T3':
// Typical range: 2.3-4.2 pg/mL
value = 2.3 + random.nextDouble() * 1.9;
break;
case 'Free T4':
// Typical range: 0.8-1.8 ng/dL
value = 0.8 + random.nextDouble() * 1.0;
break;
case 'SHBG':
// Typical range: 20-130 nmol/L
value = 20.0 + random.nextDouble() * 110.0;
break;
case 'DHT':
// Typical range: 24-65 ng/dL
value = 24.0 + random.nextDouble() * 41.0;
break;
default:
// Default range for other hormones
value = 10.0 + random.nextDouble() * 90.0;
}
// Round to 1 decimal place
value = (value * 10).round() / 10;
return HormoneReading(
name: hormoneName,
value: value,
unit: unit,
);
}
}

View file

@ -0,0 +1,232 @@
// SPDX-FileCopyrightText: © 2025 Nøkken.io <nokken.io@proton.me>
// SPDX-License-Identifier: AGPL-3.0
//
// medication_data_generator.dart
//
import 'dart:math' show Random;
import 'package:flutter/material.dart';
import 'package:nokken/src/core/constants/date_constants.dart';
import 'package:nokken/src/core/services/database/database_service.dart';
import 'package:nokken/src/features/medication_tracker/models/medication.dart';
import 'package:nokken/src/features/medication_tracker/models/medication_dose.dart';
/// A tool class to generate historical medication data
class MedicationDataGenerator {
final DatabaseService databaseService;
MedicationDataGenerator(this.databaseService);
/// Generate sample medications and adherence data for 365 days
Future<void> generateMedicationData() async {
final random = Random();
// Start date: 364 days ago from today
final endDate = DateTime.now();
final startDate = endDate.subtract(const Duration(days: 364));
debugPrint(
'Generating medication data from ${startDate.toIso8601String()} to ${endDate.toIso8601String()}');
// Check existing medications and add more if needed
final existingMeds = await databaseService.getAllMedications();
debugPrint('Found ${existingMeds.length} existing medications');
// We want to have at least 5 medications
if (existingMeds.length < 5) {
debugPrint('Creating additional sample medications...');
final targetCount = 5 - existingMeds.length;
// Get sample medications and only use as many as needed
final allSampleMeds = _createSampleMedications();
final medsToAdd = allSampleMeds.take(targetCount).toList();
for (final med in medsToAdd) {
await databaseService.insertMedication(med);
}
debugPrint('Created ${medsToAdd.length} additional medications.');
}
// Get all medications
final allMeds = await databaseService.getAllMedications();
// Generate taking records for each medication
for (final med in allMeds) {
debugPrint('Generating adherence data for ${med.name}...');
// Set adherence rate based on medication type
double adherenceRate;
if (med.medicationType == MedicationType.injection ||
med.medicationType == MedicationType.patch) {
// Higher adherence for injections and patches (96-98%)
adherenceRate = 0.96 + (random.nextDouble() * 0.02);
} else {
// Lower adherence for pills and topical (95-97%)
adherenceRate = 0.95 + (random.nextDouble() * 0.02);
}
debugPrint(
'Using adherence rate of ${(adherenceRate * 100).toStringAsFixed(1)}% for ${med.name}');
// Generate records for each day
await _generateMedicationRecords(
med, startDate, endDate, adherenceRate, random);
}
debugPrint('Successfully generated medication adherence data.');
}
/// Create 5 sample medications of different types
List<Medication> _createSampleMedications() {
final now = DateTime.now();
final allDays = Set<String>.from(DateConstants.dayMap.values);
// Common morning and evening times
final morning = DateTime(now.year, now.month, now.day, 8, 0);
final evening = DateTime(now.year, now.month, now.day, 20, 0);
final noon = DateTime(now.year, now.month, now.day, 12, 0);
return [
// Pill 1: Daily antidepressant in the morning
Medication(
name: 'Sertraline',
dosage: '50mg',
startDate: DateTime.now().subtract(const Duration(days: 400)),
frequency: 1,
timeOfDay: [morning],
daysOfWeek: allDays,
currentQuantity: 28,
refillThreshold: 7,
medicationType: MedicationType.oral,
oralSubtype: OralSubtype.tablets,
notes: 'SSRI antidepressant',
doctor: 'Dr. Smith',
pharmacy: 'Local Pharmacy',
),
// Pill 2: Multivitamin taken once daily
Medication(
name: 'Multivitamin',
dosage: '1 tablet',
startDate: DateTime.now().subtract(const Duration(days: 380)),
frequency: 1,
timeOfDay: [noon],
daysOfWeek: allDays,
currentQuantity: 60,
refillThreshold: 10,
medicationType: MedicationType.oral,
oralSubtype: OralSubtype.tablets,
),
// Topical: Gel applied twice daily
Medication(
name: 'Topical Treatment',
dosage: 'Thin layer',
startDate: DateTime.now().subtract(const Duration(days: 390)),
frequency: 2,
timeOfDay: [morning, evening],
daysOfWeek: allDays,
currentQuantity: 1,
refillThreshold: 1,
medicationType: MedicationType.topical,
topicalSubtype: TopicalSubtype.gel,
),
// Patch: Applied weekly
Medication(
name: 'Hormone Patch',
dosage: '1 patch',
startDate: DateTime.now().subtract(const Duration(days: 395)),
frequency: 1,
timeOfDay: [morning],
daysOfWeek: {'Su'}, // Applied on Sundays
currentQuantity: 4,
refillThreshold: 2,
medicationType: MedicationType.patch,
),
// Injection: Intramuscular, biweekly
Medication(
name: 'Hormone Injection',
dosage: '0.5ml',
startDate: DateTime.now().subtract(const Duration(days: 392)),
frequency: 1,
timeOfDay: [evening],
daysOfWeek: {'F'}, // Injected on Fridays
currentQuantity: 2,
refillThreshold: 1,
medicationType: MedicationType.injection,
injectionDetails: InjectionDetails(
drawingNeedleType: '18G 1.5"',
drawingNeedleCount: 8,
drawingNeedleRefills: 2,
injectingNeedleType: '23G 1"',
injectingNeedleCount: 8,
injectingNeedleRefills: 2,
syringeType: '3ml Luer Lock',
syringeCount: 8,
syringeRefills: 2,
injectionSiteNotes: 'Rotate between thighs and glutes',
frequency: InjectionFrequency.biweekly,
subtype: InjectionSubtype.intramuscular,
siteRotation: InjectionSiteRotation(
sites: [
InjectionSite(siteNumber: 1, bodyArea: InjectionBodyArea.thigh),
InjectionSite(siteNumber: 2, bodyArea: InjectionBodyArea.thigh),
],
currentSiteIndex: 0,
),
),
doctor: 'Dr. Johnson',
pharmacy: 'Specialty Pharmacy',
),
];
}
/// Generate medication taking records based on specified adherence patterns
Future<void> _generateMedicationRecords(
Medication medication,
DateTime startDate,
DateTime endDate,
double adherenceRate,
Random random) async {
int recordCount = 0;
// For each day in the range
for (int i = 0; i <= 364; i++) {
final date = startDate.add(Duration(days: i));
// Check if this medication is scheduled for this day
if (medication.isDueOnDate(date)) {
// For each time slot
for (int timeIndex = 0; timeIndex < medication.frequency; timeIndex++) {
final timeSlot = timeIndex < medication.timeOfDay.length
? medication.timeOfDay[timeIndex].hour.toString()
: '$timeIndex';
// Create a proper MedicationDose object
final dose = MedicationDose(
medicationId: medication.id,
date: date,
timeSlot: timeSlot,
);
// Generate a custom key from the dose plus a unique identifier
final customKey = '${dose.toKey()}-historical-$i';
// Determine if the dose was taken based on adherence rate
final wasTaken = random.nextDouble() <= adherenceRate;
// Save the taking record
await databaseService.setMedicationTakenWithCustomKey(
medication.id, date, timeSlot, wasTaken, customKey);
if (wasTaken) {
recordCount++;
}
}
}
}
debugPrint('Generated $recordCount taking records for ${medication.name}');
}
}

View file

@ -0,0 +1,226 @@
// SPDX-FileCopyrightText: © 2025 Nøkken.io <nokken.io@proton.me>
// SPDX-License-Identifier: AGPL-3.0
//
// mood_data_generator.dart
//
import 'dart:math' show Random;
import 'package:flutter/material.dart';
import 'package:nokken/src/core/services/database/database_service.dart';
import 'package:nokken/src/core/services/database/database_service_mood.dart';
import 'package:nokken/src/features/mood_tracker/models/mood_entry.dart';
import 'package:uuid/uuid.dart';
/// A tool class to generate historical mood data
class MoodDataGenerator {
final DatabaseService databaseService;
MoodDataGenerator(this.databaseService);
/// Generate 365 days of mood entries
Future<void> generateMoodEntries() async {
final random = Random();
// Start date: 364 days ago from today
final endDate = DateTime.now();
final startDate = endDate.subtract(const Duration(days: 364));
debugPrint(
'Generating mood entries from ${startDate.toIso8601String()} to ${endDate.toIso8601String()}');
// Generate an entry for each day
for (int i = 0; i <= 364; i++) {
final date = startDate.add(Duration(days: i));
// Generate random mood entry
final entry = _generateRandomMoodEntry(date, random);
// Insert into database
await databaseService.insertMoodEntry(entry);
// Print progress
if (i % 30 == 0) {
debugPrint('Generated ${i + 1} entries...');
}
}
debugPrint('Successfully generated 365 mood entries.');
}
/// Generate a random but realistic mood entry for the given date
MoodEntry _generateRandomMoodEntry(DateTime date, Random random) {
// Generate a unique ID
final id = const Uuid().v4();
// Generate a base mood index with some weekly and seasonal patterns
int baseMoodModifier = 0;
// Weekday effects: people often feel better on weekends, worse on Mondays
if (date.weekday == DateTime.saturday || date.weekday == DateTime.sunday) {
baseMoodModifier =
random.nextDouble() < 0.7 ? 1 : 0; // Better mood on weekends
} else if (date.weekday == DateTime.monday) {
baseMoodModifier =
random.nextDouble() < 0.6 ? -1 : 0; // Worse mood on Mondays
}
// Seasonal effects: worse in winter, better in summer
final month = date.month;
int seasonalModifier = 0;
if (month >= 11 || month <= 2) {
// Winter months
seasonalModifier = random.nextDouble() < 0.6 ? -1 : 0;
} else if (month >= 5 && month <= 8) {
// Summer months
seasonalModifier = random.nextDouble() < 0.6 ? 1 : 0;
}
// Calculate final mood index with modifiers and randomness
// Assuming mood from terrible (0) to excellent (4)
int moodIndex =
2 + baseMoodModifier + seasonalModifier; // Start from neutral (2)
moodIndex += (random.nextInt(3) - 1); // Add -1, 0, or 1 for randomness
moodIndex = moodIndex.clamp(0, 4); // Ensure within valid range
// Convert index to actual MoodRating enum
final mood = MoodRating.values[moodIndex];
// Generate 1-6 random emotions
final emotionCount = random.nextInt(6) + 1;
final emotions = <Emotion>{};
while (emotions.length < emotionCount &&
emotions.length < Emotion.values.length) {
final emotionIndex = random.nextInt(Emotion.values.length);
emotions.add(Emotion.values[emotionIndex]);
}
// Decide which health metrics to include (3 to all)
final healthMetricsCount = random.nextInt(5) + 3; // 3 to 7 metrics
final healthMetricsToInclude = List.generate(7, (index) => index)
..shuffle(random);
final selectedHealthMetrics =
healthMetricsToInclude.take(healthMetricsCount).toList();
// Helper function to generate a correlated index
int correlatedIndex(
int baseIndex, double correlationStrength, int maxIndex) {
if (random.nextDouble() < correlationStrength) {
// Correlated value
final variation = random.nextInt(3) - 1; // -1, 0, or 1
return (baseIndex + variation).clamp(0, maxIndex - 1);
} else {
// Random value
return random.nextInt(maxIndex);
}
}
// Generate health metrics
SleepQuality? sleepQuality;
EnergyLevel? energyLevel;
LibidoLevel? libidoLevel;
AppetiteLevel? appetiteLevel;
FocusLevel? focusLevel;
DysphoriaLevel? dysphoriaLevel;
ExerciseLevel? exerciseLevel;
// Sleep quality - somewhat correlated with mood
if (selectedHealthMetrics.contains(0)) {
final sleepIndex =
correlatedIndex(moodIndex, 0.7, SleepQuality.values.length);
sleepQuality = SleepQuality.values[sleepIndex];
}
// Energy level - often follows sleep quality if available
if (selectedHealthMetrics.contains(1)) {
int energyIndex;
if (sleepQuality != null && random.nextDouble() < 0.8) {
// Correlate with sleep
energyIndex = correlatedIndex(SleepQuality.values.indexOf(sleepQuality),
0.8, EnergyLevel.values.length);
} else {
// Correlate with mood
energyIndex =
correlatedIndex(moodIndex, 0.6, EnergyLevel.values.length);
}
energyLevel = EnergyLevel.values[energyIndex];
}
// Libido level - moderately correlated with mood
if (selectedHealthMetrics.contains(2)) {
final libidoIndex =
correlatedIndex(moodIndex, 0.5, LibidoLevel.values.length);
libidoLevel = LibidoLevel.values[libidoIndex];
}
// Appetite level - less correlated with mood
if (selectedHealthMetrics.contains(3)) {
final appetiteIndex =
correlatedIndex(moodIndex, 0.4, AppetiteLevel.values.length);
appetiteLevel = AppetiteLevel.values[appetiteIndex];
}
// Focus level - often correlates with sleep and energy
if (selectedHealthMetrics.contains(4)) {
int focusIndex;
if (sleepQuality != null &&
energyLevel != null &&
random.nextDouble() < 0.7) {
// Derive from average of sleep and energy
final avgIndex = (SleepQuality.values.indexOf(sleepQuality) +
EnergyLevel.values.indexOf(energyLevel)) ~/
2;
focusIndex = correlatedIndex(avgIndex, 0.8, FocusLevel.values.length);
} else {
// Correlate with mood
focusIndex = correlatedIndex(moodIndex, 0.6, FocusLevel.values.length);
}
focusLevel = FocusLevel.values[focusIndex];
}
// Dysphoria level - often inversely correlates with mood
if (selectedHealthMetrics.contains(5)) {
// Invert the mood index for dysphoria correlation (higher mood = lower dysphoria)
final invertedMood = 4 - moodIndex; // Assuming 5 mood levels (0-4)
final dysphoriaIndex =
correlatedIndex(invertedMood, 0.75, DysphoriaLevel.values.length);
dysphoriaLevel = DysphoriaLevel.values[dysphoriaIndex];
}
// Exercise level - less strongly correlated with other metrics
if (selectedHealthMetrics.contains(6)) {
final exerciseIndex = random.nextInt(ExerciseLevel.values.length);
exerciseLevel = ExerciseLevel.values[exerciseIndex];
}
// Generate optional notes (30% chance)
String? notes;
if (random.nextDouble() < 0.3) {
final noteTemplates = [
"Feeling ${moodIndex > 2 ? 'pretty good' : 'a bit down'} today.",
"Today was ${moodIndex > 3 ? 'excellent' : moodIndex > 2 ? 'decent' : 'challenging'}.",
"${moodIndex > 3 ? 'Great' : moodIndex > 2 ? 'Good' : 'Tough'} day overall.",
"Noticed ${sleepQuality != null ? (SleepQuality.values.indexOf(sleepQuality) > 2 ? 'good sleep' : 'poor sleep') : 'fluctuating energy'} today.",
"Mood tracker note for ${date.day}/${date.month}/${date.year}.",
"${energyLevel != null && EnergyLevel.values.indexOf(energyLevel) > 2 ? 'High energy' : 'Low energy'} but ${moodIndex > 2 ? 'good spirits' : 'feeling down'}.",
"Trying to stay ${moodIndex < 2 ? 'positive despite challenges' : 'grateful for the good things'}.",
];
notes = noteTemplates[random.nextInt(noteTemplates.length)];
}
// Create and return the mood entry
return MoodEntry(
id: id,
date: date,
mood: mood,
emotions: emotions,
notes: notes,
sleepQuality: sleepQuality,
energyLevel: energyLevel,
libidoLevel: libidoLevel,
appetiteLevel: appetiteLevel,
focusLevel: focusLevel,
dysphoriaLevel: dysphoriaLevel,
exerciseLevel: exerciseLevel,
);
}
}