mirror of
https://github.com/vleeuwenmenno/supplements.git
synced 2025-09-11 18:29:12 +02:00
feat: Add settings provider for theme and time range management
- Implemented SettingsProvider to manage user preferences for theme options and time ranges for reminders. - Added persistent reminder settings with configurable retry intervals and maximum attempts. - Created UI for settings screen to allow users to customize their preferences. - Integrated shared_preferences for persistent storage of user settings. feat: Introduce Ingredient model - Created Ingredient model to represent nutritional components with properties for id, name, amount, and unit. - Added methods for serialization and deserialization of Ingredient objects. feat: Develop Archived Supplements Screen - Implemented ArchivedSupplementsScreen to display archived supplements with options to unarchive or delete. - Added UI components for listing archived supplements and handling user interactions. chore: Update dependencies in pubspec.yaml and pubspec.lock - Updated shared_preferences dependency to the latest version. - Removed flutter_datetime_picker_plus dependency and added file dependency. - Updated Flutter SDK constraint to >=3.27.0.
This commit is contained in:
64
lib/models/ingredient.dart
Normal file
64
lib/models/ingredient.dart
Normal file
@@ -0,0 +1,64 @@
|
||||
class Ingredient {
|
||||
final int? id;
|
||||
final String name; // e.g., "Vitamin K2", "Vitamin D3"
|
||||
final double amount; // e.g., 75, 20
|
||||
final String unit; // e.g., "mcg", "mg", "IU"
|
||||
|
||||
const Ingredient({
|
||||
this.id,
|
||||
required this.name,
|
||||
required this.amount,
|
||||
required this.unit,
|
||||
});
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
'id': id,
|
||||
'name': name,
|
||||
'amount': amount,
|
||||
'unit': unit,
|
||||
};
|
||||
}
|
||||
|
||||
factory Ingredient.fromMap(Map<String, dynamic> map) {
|
||||
return Ingredient(
|
||||
id: map['id'],
|
||||
name: map['name'],
|
||||
amount: map['amount']?.toDouble() ?? 0.0,
|
||||
unit: map['unit'],
|
||||
);
|
||||
}
|
||||
|
||||
Ingredient copyWith({
|
||||
int? id,
|
||||
String? name,
|
||||
double? amount,
|
||||
String? unit,
|
||||
}) {
|
||||
return Ingredient(
|
||||
id: id ?? this.id,
|
||||
name: name ?? this.name,
|
||||
amount: amount ?? this.amount,
|
||||
unit: unit ?? this.unit,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return '$amount$unit $name';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (identical(this, other)) return true;
|
||||
return other is Ingredient &&
|
||||
other.name == name &&
|
||||
other.amount == amount &&
|
||||
other.unit == unit;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
return name.hashCode ^ amount.hashCode ^ unit.hashCode;
|
||||
}
|
||||
}
|
@@ -1,9 +1,12 @@
|
||||
import 'ingredient.dart';
|
||||
import 'dart:convert';
|
||||
|
||||
class Supplement {
|
||||
final int? id;
|
||||
final String name;
|
||||
final double dosageAmount; // Amount per unit (e.g., 187mg)
|
||||
final String? brand;
|
||||
final List<Ingredient> ingredients;
|
||||
final int numberOfUnits; // Number of units to take (e.g., 2 capsules)
|
||||
final String unit; // mg, g, ml, etc.
|
||||
final String unitType; // capsules, tablets, ml, etc.
|
||||
final int frequencyPerDay;
|
||||
final List<String> reminderTimes; // e.g., ['08:00', '20:00']
|
||||
@@ -14,9 +17,9 @@ class Supplement {
|
||||
Supplement({
|
||||
this.id,
|
||||
required this.name,
|
||||
required this.dosageAmount,
|
||||
this.brand,
|
||||
this.ingredients = const [],
|
||||
required this.numberOfUnits,
|
||||
required this.unit,
|
||||
required this.unitType,
|
||||
required this.frequencyPerDay,
|
||||
required this.reminderTimes,
|
||||
@@ -25,16 +28,38 @@ class Supplement {
|
||||
this.isActive = true,
|
||||
});
|
||||
|
||||
// Helper getter for total dosage per intake
|
||||
double get totalDosagePerIntake => dosageAmount * numberOfUnits;
|
||||
// Helper getters
|
||||
double get totalDosagePerIntake {
|
||||
// This concept doesn't apply well to multi-ingredient supplements
|
||||
// Return 0 as it should be handled per ingredient
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
// Get formatted ingredients string for display
|
||||
String get ingredientsDisplay {
|
||||
if (ingredients.isEmpty) {
|
||||
return 'No ingredients specified';
|
||||
}
|
||||
return ingredients.map((ingredient) =>
|
||||
'${ingredient.amount * numberOfUnits}${ingredient.unit} ${ingredient.name}'
|
||||
).join(', ');
|
||||
}
|
||||
|
||||
// Get ingredients per single unit
|
||||
String get ingredientsPerUnit {
|
||||
if (ingredients.isEmpty) {
|
||||
return 'No ingredients specified';
|
||||
}
|
||||
return ingredients.map((ingredient) => ingredient.toString()).join(', ');
|
||||
}
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
'id': id,
|
||||
'name': name,
|
||||
'dosageAmount': dosageAmount,
|
||||
'brand': brand,
|
||||
'ingredients': jsonEncode(ingredients.map((ingredient) => ingredient.toMap()).toList()),
|
||||
'numberOfUnits': numberOfUnits,
|
||||
'unit': unit,
|
||||
'unitType': unitType,
|
||||
'frequencyPerDay': frequencyPerDay,
|
||||
'reminderTimes': reminderTimes.join(','),
|
||||
@@ -45,13 +70,29 @@ class Supplement {
|
||||
}
|
||||
|
||||
factory Supplement.fromMap(Map<String, dynamic> map) {
|
||||
List<Ingredient> ingredients = [];
|
||||
|
||||
// Try to parse ingredients if they exist
|
||||
if (map['ingredients'] != null && map['ingredients'].isNotEmpty) {
|
||||
try {
|
||||
final ingredientsJson = map['ingredients'] as String;
|
||||
final ingredientsList = jsonDecode(ingredientsJson) as List;
|
||||
ingredients = ingredientsList
|
||||
.map((ingredient) => Ingredient.fromMap(ingredient as Map<String, dynamic>))
|
||||
.toList();
|
||||
} catch (e) {
|
||||
// If parsing fails, fall back to empty list
|
||||
ingredients = [];
|
||||
}
|
||||
}
|
||||
|
||||
return Supplement(
|
||||
id: map['id'],
|
||||
name: map['name'],
|
||||
dosageAmount: map['dosageAmount']?.toDouble() ?? map['dosage']?.toDouble() ?? 0.0, // Backwards compatibility
|
||||
numberOfUnits: map['numberOfUnits'] ?? 1, // Default to 1 for backwards compatibility
|
||||
unit: map['unit'],
|
||||
unitType: map['unitType'] ?? 'units', // Default unit type for backwards compatibility
|
||||
brand: map['brand'],
|
||||
ingredients: ingredients,
|
||||
numberOfUnits: map['numberOfUnits'] ?? 1,
|
||||
unitType: map['unitType'] ?? 'units',
|
||||
frequencyPerDay: map['frequencyPerDay'],
|
||||
reminderTimes: map['reminderTimes'].split(','),
|
||||
notes: map['notes'],
|
||||
@@ -63,9 +104,9 @@ class Supplement {
|
||||
Supplement copyWith({
|
||||
int? id,
|
||||
String? name,
|
||||
double? dosageAmount,
|
||||
String? brand,
|
||||
List<Ingredient>? ingredients,
|
||||
int? numberOfUnits,
|
||||
String? unit,
|
||||
String? unitType,
|
||||
int? frequencyPerDay,
|
||||
List<String>? reminderTimes,
|
||||
@@ -76,9 +117,9 @@ class Supplement {
|
||||
return Supplement(
|
||||
id: id ?? this.id,
|
||||
name: name ?? this.name,
|
||||
dosageAmount: dosageAmount ?? this.dosageAmount,
|
||||
brand: brand ?? this.brand,
|
||||
ingredients: ingredients ?? this.ingredients,
|
||||
numberOfUnits: numberOfUnits ?? this.numberOfUnits,
|
||||
unit: unit ?? this.unit,
|
||||
unitType: unitType ?? this.unitType,
|
||||
frequencyPerDay: frequencyPerDay ?? this.frequencyPerDay,
|
||||
reminderTimes: reminderTimes ?? this.reminderTimes,
|
||||
|
Reference in New Issue
Block a user