mirror of
https://github.com/vleeuwenmenno/supplements.git
synced 2025-09-11 18:29:12 +02:00
adds syncing
This commit is contained in:
@@ -1,7 +1,9 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
||||
|
||||
import '../models/supplement.dart';
|
||||
import '../models/supplement_intake.dart';
|
||||
import '../services/database_helper.dart';
|
||||
@@ -19,17 +21,30 @@ class SupplementProvider with ChangeNotifier, WidgetsBindingObserver {
|
||||
Timer? _dateChangeTimer;
|
||||
DateTime _lastDateCheck = DateTime.now();
|
||||
|
||||
// Callback for triggering sync when data changes
|
||||
VoidCallback? _onDataChanged;
|
||||
|
||||
List<Supplement> get supplements => _supplements;
|
||||
List<Map<String, dynamic>> get todayIntakes => _todayIntakes;
|
||||
List<Map<String, dynamic>> get monthlyIntakes => _monthlyIntakes;
|
||||
bool get isLoading => _isLoading;
|
||||
|
||||
/// Set callback for triggering sync when data changes
|
||||
void setOnDataChangedCallback(VoidCallback? callback) {
|
||||
_onDataChanged = callback;
|
||||
}
|
||||
|
||||
/// Trigger sync if callback is set
|
||||
void _triggerSyncIfEnabled() {
|
||||
_onDataChanged?.call();
|
||||
}
|
||||
|
||||
Future<void> initialize() async {
|
||||
// Add this provider as an observer for app lifecycle changes
|
||||
WidgetsBinding.instance.addObserver(this);
|
||||
|
||||
|
||||
await _notificationService.initialize();
|
||||
|
||||
|
||||
// Set up the callback for handling supplement intake from notifications
|
||||
print('📱 Setting up notification callback...');
|
||||
_notificationService.setTakeSupplementCallback((supplementId, supplementName, units, unitType) {
|
||||
@@ -38,18 +53,18 @@ class SupplementProvider with ChangeNotifier, WidgetsBindingObserver {
|
||||
print('📱 Supplement Name: $supplementName');
|
||||
print('📱 Units: $units');
|
||||
print('📱 Unit Type: $unitType');
|
||||
|
||||
|
||||
// Record the intake when user taps "Take" on notification
|
||||
recordIntake(supplementId, 0.0, unitsTaken: units);
|
||||
print('📱 Intake recorded successfully');
|
||||
print('📱 === CALLBACK COMPLETE ===');
|
||||
|
||||
|
||||
if (kDebugMode) {
|
||||
print('📱 Recorded intake from notification: $supplementName ($units $unitType)');
|
||||
}
|
||||
});
|
||||
print('📱 Notification callback setup complete');
|
||||
|
||||
|
||||
// Request permissions with error handling
|
||||
try {
|
||||
await _notificationService.requestPermissions();
|
||||
@@ -59,16 +74,16 @@ class SupplementProvider with ChangeNotifier, WidgetsBindingObserver {
|
||||
}
|
||||
// Continue without notifications rather than crashing
|
||||
}
|
||||
|
||||
|
||||
await loadSupplements();
|
||||
await loadTodayIntakes();
|
||||
|
||||
|
||||
// Reschedule notifications for all active supplements to ensure persistence
|
||||
await _rescheduleAllNotifications();
|
||||
|
||||
|
||||
// Start periodic checking for persistent reminders (every 5 minutes)
|
||||
_startPersistentReminderCheck();
|
||||
|
||||
|
||||
// Start date change monitoring to reset daily intake status
|
||||
_startDateChangeMonitoring();
|
||||
}
|
||||
@@ -76,7 +91,7 @@ class SupplementProvider with ChangeNotifier, WidgetsBindingObserver {
|
||||
void _startPersistentReminderCheck() {
|
||||
// Cancel any existing timer
|
||||
_persistentReminderTimer?.cancel();
|
||||
|
||||
|
||||
// Check every 5 minutes for persistent reminders
|
||||
_persistentReminderTimer = Timer.periodic(const Duration(minutes: 5), (timer) async {
|
||||
try {
|
||||
@@ -88,7 +103,7 @@ class SupplementProvider with ChangeNotifier, WidgetsBindingObserver {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Also check immediately
|
||||
_checkPersistentReminders();
|
||||
}
|
||||
@@ -96,23 +111,23 @@ class SupplementProvider with ChangeNotifier, WidgetsBindingObserver {
|
||||
void _startDateChangeMonitoring() {
|
||||
// Cancel any existing timer
|
||||
_dateChangeTimer?.cancel();
|
||||
|
||||
|
||||
// Check every minute if the date has changed
|
||||
_dateChangeTimer = Timer.periodic(const Duration(minutes: 1), (timer) async {
|
||||
final now = DateTime.now();
|
||||
final currentDate = DateTime(now.year, now.month, now.day);
|
||||
final lastCheckDate = DateTime(_lastDateCheck.year, _lastDateCheck.month, _lastDateCheck.day);
|
||||
|
||||
|
||||
if (currentDate != lastCheckDate) {
|
||||
if (kDebugMode) {
|
||||
print('Date changed detected: ${lastCheckDate} -> ${currentDate}');
|
||||
print('Refreshing today\'s intakes for new day...');
|
||||
}
|
||||
|
||||
|
||||
// Date has changed, refresh today's intakes
|
||||
_lastDateCheck = now;
|
||||
await loadTodayIntakes();
|
||||
|
||||
|
||||
if (kDebugMode) {
|
||||
print('Today\'s intakes refreshed for new day');
|
||||
}
|
||||
@@ -164,7 +179,7 @@ class SupplementProvider with ChangeNotifier, WidgetsBindingObserver {
|
||||
@override
|
||||
void didChangeAppLifecycleState(AppLifecycleState state) {
|
||||
super.didChangeAppLifecycleState(state);
|
||||
|
||||
|
||||
if (state == AppLifecycleState.resumed) {
|
||||
// App came back to foreground, check if date changed
|
||||
if (kDebugMode) {
|
||||
@@ -178,7 +193,7 @@ class SupplementProvider with ChangeNotifier, WidgetsBindingObserver {
|
||||
if (kDebugMode) {
|
||||
print('📱 Rescheduling notifications for all active supplements...');
|
||||
}
|
||||
|
||||
|
||||
for (final supplement in _supplements) {
|
||||
if (supplement.reminderTimes.isNotEmpty) {
|
||||
try {
|
||||
@@ -190,7 +205,7 @@ class SupplementProvider with ChangeNotifier, WidgetsBindingObserver {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (kDebugMode) {
|
||||
print('📱 Finished rescheduling notifications');
|
||||
}
|
||||
@@ -224,7 +239,7 @@ class SupplementProvider with ChangeNotifier, WidgetsBindingObserver {
|
||||
final id = await _databaseHelper.insertSupplement(supplement);
|
||||
print('Supplement inserted with ID: $id');
|
||||
final newSupplement = supplement.copyWith(id: id);
|
||||
|
||||
|
||||
// Schedule notifications (skip if there's an error)
|
||||
try {
|
||||
await _notificationService.scheduleSupplementReminders(newSupplement);
|
||||
@@ -232,9 +247,12 @@ class SupplementProvider with ChangeNotifier, WidgetsBindingObserver {
|
||||
} catch (notificationError) {
|
||||
print('Warning: Could not schedule notifications: $notificationError');
|
||||
}
|
||||
|
||||
|
||||
await loadSupplements();
|
||||
print('Supplements reloaded, count: ${_supplements.length}');
|
||||
|
||||
// Trigger sync after adding supplement
|
||||
_triggerSyncIfEnabled();
|
||||
} catch (e) {
|
||||
print('Error adding supplement: $e');
|
||||
if (kDebugMode) {
|
||||
@@ -247,11 +265,14 @@ class SupplementProvider with ChangeNotifier, WidgetsBindingObserver {
|
||||
Future<void> updateSupplement(Supplement supplement) async {
|
||||
try {
|
||||
await _databaseHelper.updateSupplement(supplement);
|
||||
|
||||
|
||||
// Reschedule notifications
|
||||
await _notificationService.scheduleSupplementReminders(supplement);
|
||||
|
||||
|
||||
await loadSupplements();
|
||||
|
||||
// Trigger sync after updating supplement
|
||||
_triggerSyncIfEnabled();
|
||||
} catch (e) {
|
||||
if (kDebugMode) {
|
||||
print('Error updating supplement: $e');
|
||||
@@ -262,11 +283,14 @@ class SupplementProvider with ChangeNotifier, WidgetsBindingObserver {
|
||||
Future<void> deleteSupplement(int id) async {
|
||||
try {
|
||||
await _databaseHelper.deleteSupplement(id);
|
||||
|
||||
|
||||
// Cancel notifications
|
||||
await _notificationService.cancelSupplementReminders(id);
|
||||
|
||||
|
||||
await loadSupplements();
|
||||
|
||||
// Trigger sync after deleting supplement
|
||||
_triggerSyncIfEnabled();
|
||||
} catch (e) {
|
||||
if (kDebugMode) {
|
||||
print('Error deleting supplement: $e');
|
||||
@@ -286,7 +310,10 @@ class SupplementProvider with ChangeNotifier, WidgetsBindingObserver {
|
||||
|
||||
await _databaseHelper.insertIntake(intake);
|
||||
await loadTodayIntakes();
|
||||
|
||||
|
||||
// Trigger sync after recording intake
|
||||
_triggerSyncIfEnabled();
|
||||
|
||||
// Show confirmation notification
|
||||
final supplement = _supplements.firstWhere((s) => s.id == supplementId);
|
||||
final unitsText = unitsTaken != null && unitsTaken != 1 ? '${unitsTaken.toStringAsFixed(unitsTaken % 1 == 0 ? 0 : 1)} ${supplement.unitType}' : '';
|
||||
@@ -307,16 +334,16 @@ class SupplementProvider with ChangeNotifier, WidgetsBindingObserver {
|
||||
if (kDebugMode) {
|
||||
print('Loading intakes for date: ${today.year}-${today.month}-${today.day}');
|
||||
}
|
||||
|
||||
|
||||
_todayIntakes = await _databaseHelper.getIntakesWithSupplementsForDate(today);
|
||||
|
||||
|
||||
if (kDebugMode) {
|
||||
print('Loaded ${_todayIntakes.length} intakes for today');
|
||||
for (var intake in _todayIntakes) {
|
||||
print(' - Supplement ID: ${intake['supplement_id']}, taken at: ${intake['takenAt']}');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
notifyListeners();
|
||||
} catch (e) {
|
||||
if (kDebugMode) {
|
||||
@@ -356,6 +383,9 @@ class SupplementProvider with ChangeNotifier, WidgetsBindingObserver {
|
||||
await loadMonthlyIntakes(DateTime.now().year, DateTime.now().month);
|
||||
}
|
||||
notifyListeners();
|
||||
|
||||
// Trigger sync after deleting intake
|
||||
_triggerSyncIfEnabled();
|
||||
} catch (e) {
|
||||
if (kDebugMode) {
|
||||
print('Error deleting intake: $e');
|
||||
@@ -385,13 +415,13 @@ class SupplementProvider with ChangeNotifier, WidgetsBindingObserver {
|
||||
final now = DateTime.now();
|
||||
final currentDate = DateTime(now.year, now.month, now.day);
|
||||
final lastCheckDate = DateTime(_lastDateCheck.year, _lastDateCheck.month, _lastDateCheck.day);
|
||||
|
||||
|
||||
if (kDebugMode) {
|
||||
print('Force checking date change...');
|
||||
print('Current date: $currentDate');
|
||||
print('Last check date: $lastCheckDate');
|
||||
}
|
||||
|
||||
|
||||
if (currentDate != lastCheckDate) {
|
||||
if (kDebugMode) {
|
||||
print('Date change detected, refreshing intakes...');
|
||||
@@ -425,6 +455,9 @@ class SupplementProvider with ChangeNotifier, WidgetsBindingObserver {
|
||||
await _databaseHelper.archiveSupplement(supplementId);
|
||||
await loadSupplements(); // Refresh active supplements
|
||||
await loadArchivedSupplements(); // Refresh archived supplements
|
||||
|
||||
// Trigger sync after archiving supplement
|
||||
_triggerSyncIfEnabled();
|
||||
} catch (e) {
|
||||
if (kDebugMode) {
|
||||
print('Error archiving supplement: $e');
|
||||
@@ -437,6 +470,9 @@ class SupplementProvider with ChangeNotifier, WidgetsBindingObserver {
|
||||
await _databaseHelper.unarchiveSupplement(supplementId);
|
||||
await loadSupplements(); // Refresh active supplements
|
||||
await loadArchivedSupplements(); // Refresh archived supplements
|
||||
|
||||
// Trigger sync after unarchiving supplement
|
||||
_triggerSyncIfEnabled();
|
||||
} catch (e) {
|
||||
if (kDebugMode) {
|
||||
print('Error unarchiving supplement: $e');
|
||||
@@ -448,6 +484,9 @@ class SupplementProvider with ChangeNotifier, WidgetsBindingObserver {
|
||||
try {
|
||||
await _databaseHelper.deleteSupplement(supplementId);
|
||||
await loadArchivedSupplements(); // Refresh archived supplements
|
||||
|
||||
// Trigger sync after deleting archived supplement
|
||||
_triggerSyncIfEnabled();
|
||||
} catch (e) {
|
||||
if (kDebugMode) {
|
||||
print('Error deleting archived supplement: $e');
|
||||
|
Reference in New Issue
Block a user