Files
supplements/lib/models/supplement.dart

201 lines
5.8 KiB
Dart

import 'dart:convert';
import 'package:uuid/uuid.dart';
import '../services/database_sync_service.dart';
import 'ingredient.dart';
class Supplement {
final int? id;
final String name;
final String? brand;
final List<Ingredient> ingredients;
final int numberOfUnits; // Number of units to take (e.g., 2 capsules)
final String unitType; // capsules, tablets, ml, etc.
final int frequencyPerDay;
final List<String> reminderTimes; // e.g., ['08:00', '20:00']
final String? notes;
final DateTime createdAt;
final bool isActive;
// Sync metadata
final String syncId;
final DateTime lastModified;
final RecordSyncStatus syncStatus;
final bool isDeleted;
Supplement({
this.id,
required this.name,
this.brand,
this.ingredients = const [],
required this.numberOfUnits,
required this.unitType,
required this.frequencyPerDay,
required this.reminderTimes,
this.notes,
required this.createdAt,
this.isActive = true,
String? syncId,
DateTime? lastModified,
this.syncStatus = RecordSyncStatus.pending,
this.isDeleted = false,
}) : syncId = syncId ?? const Uuid().v4(),
lastModified = lastModified ?? DateTime.now();
// 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() {
final map = <String, dynamic>{
'name': name,
'brand': brand,
'ingredients': jsonEncode(ingredients.map((ingredient) => ingredient.toMap()).toList()),
'numberOfUnits': numberOfUnits,
'unitType': unitType,
'frequencyPerDay': frequencyPerDay,
'reminderTimes': reminderTimes.join(','),
'notes': notes,
'createdAt': createdAt.toIso8601String(),
'isActive': isActive ? 1 : 0,
'syncId': syncId,
'lastModified': lastModified.toIso8601String(),
'syncStatus': syncStatus.name,
'isDeleted': isDeleted ? 1 : 0,
};
if (id != null) {
map['id'] = id;
}
return map;
}
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'],
brand: map['brand'],
ingredients: ingredients,
numberOfUnits: map['numberOfUnits'] ?? 1,
unitType: map['unitType'] ?? 'units',
frequencyPerDay: map['frequencyPerDay'],
reminderTimes: map['reminderTimes'].split(','),
notes: map['notes'],
createdAt: DateTime.parse(map['createdAt']),
isActive: map['isActive'] == 1,
syncId: map['syncId'] ?? const Uuid().v4(),
lastModified: map['lastModified'] != null
? DateTime.parse(map['lastModified'])
: DateTime.now(),
syncStatus: map['syncStatus'] != null
? RecordSyncStatus.values.firstWhere(
(e) => e.name == map['syncStatus'],
orElse: () => RecordSyncStatus.pending,
)
: RecordSyncStatus.pending,
isDeleted: (map['isDeleted'] ?? 0) == 1,
);
}
Supplement copyWith({
int? id,
bool setNullId = false,
String? name,
String? brand,
List<Ingredient>? ingredients,
int? numberOfUnits,
String? unitType,
int? frequencyPerDay,
List<String>? reminderTimes,
String? notes,
DateTime? createdAt,
bool? isActive,
String? syncId,
bool newSyncId = false,
DateTime? lastModified,
RecordSyncStatus? syncStatus,
bool? isDeleted,
}) {
return Supplement(
id: setNullId ? null : (id ?? this.id),
name: name ?? this.name,
brand: brand ?? this.brand,
ingredients: ingredients ?? this.ingredients,
numberOfUnits: numberOfUnits ?? this.numberOfUnits,
unitType: unitType ?? this.unitType,
frequencyPerDay: frequencyPerDay ?? this.frequencyPerDay,
reminderTimes: reminderTimes ?? this.reminderTimes,
notes: notes ?? this.notes,
createdAt: createdAt ?? this.createdAt,
isActive: isActive ?? this.isActive,
syncId: newSyncId ? null : (syncId ?? this.syncId),
lastModified: lastModified ?? this.lastModified,
syncStatus: syncStatus ?? this.syncStatus,
isDeleted: isDeleted ?? this.isDeleted,
);
}
/// Create a new supplement with updated sync status and timestamp
Supplement markAsModified() {
return copyWith(
lastModified: DateTime.now(),
syncStatus: RecordSyncStatus.modified,
);
}
/// Create a new supplement marked as synced
Supplement markAsSynced() {
return copyWith(
syncStatus: RecordSyncStatus.synced,
);
}
/// Create a new supplement marked for deletion
Supplement markAsDeleted() {
return copyWith(
isDeleted: true,
lastModified: DateTime.now(),
syncStatus: RecordSyncStatus.modified,
);
}
}