226 lines
8.3 KiB
Dart
226 lines
8.3 KiB
Dart
// 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,
|
|
);
|
|
}
|
|
}
|