mirror of
https://github.com/vleeuwenmenno/supplements.git
synced 2025-09-11 18:29:12 +02:00
feat: adds auto sync feature and fixes UI a bit up
This commit is contained in:
@@ -9,7 +9,7 @@ enum ThemeOption {
|
||||
|
||||
class SettingsProvider extends ChangeNotifier {
|
||||
ThemeOption _themeOption = ThemeOption.system;
|
||||
|
||||
|
||||
// Time range settings (stored as hours, 0-23)
|
||||
int _morningStart = 5;
|
||||
int _morningEnd = 10;
|
||||
@@ -19,14 +19,18 @@ class SettingsProvider extends ChangeNotifier {
|
||||
int _eveningEnd = 22;
|
||||
int _nightStart = 23;
|
||||
int _nightEnd = 4;
|
||||
|
||||
|
||||
// Persistent reminder settings
|
||||
bool _persistentReminders = true;
|
||||
int _reminderRetryInterval = 5; // minutes
|
||||
int _maxRetryAttempts = 3;
|
||||
|
||||
|
||||
// Auto-sync settings
|
||||
bool _autoSyncEnabled = false;
|
||||
int _autoSyncDebounceSeconds = 5;
|
||||
|
||||
ThemeOption get themeOption => _themeOption;
|
||||
|
||||
|
||||
// Time range getters
|
||||
int get morningStart => _morningStart;
|
||||
int get morningEnd => _morningEnd;
|
||||
@@ -36,22 +40,26 @@ class SettingsProvider extends ChangeNotifier {
|
||||
int get eveningEnd => _eveningEnd;
|
||||
int get nightStart => _nightStart;
|
||||
int get nightEnd => _nightEnd;
|
||||
|
||||
|
||||
// Persistent reminder getters
|
||||
bool get persistentReminders => _persistentReminders;
|
||||
int get reminderRetryInterval => _reminderRetryInterval;
|
||||
int get maxRetryAttempts => _maxRetryAttempts;
|
||||
|
||||
|
||||
// Auto-sync getters
|
||||
bool get autoSyncEnabled => _autoSyncEnabled;
|
||||
int get autoSyncDebounceSeconds => _autoSyncDebounceSeconds;
|
||||
|
||||
// Helper method to get formatted time ranges for display
|
||||
String get morningRange => '${_formatHour(_morningStart)} - ${_formatHour((_morningEnd + 1) % 24)}';
|
||||
String get afternoonRange => '${_formatHour(_afternoonStart)} - ${_formatHour((_afternoonEnd + 1) % 24)}';
|
||||
String get eveningRange => '${_formatHour(_eveningStart)} - ${_formatHour((_eveningEnd + 1) % 24)}';
|
||||
String get nightRange => '${_formatHour(_nightStart)} - ${_formatHour((_nightEnd + 1) % 24)}';
|
||||
|
||||
|
||||
String _formatHour(int hour) {
|
||||
return '${hour.toString().padLeft(2, '0')}:00';
|
||||
}
|
||||
|
||||
|
||||
ThemeMode get themeMode {
|
||||
switch (_themeOption) {
|
||||
case ThemeOption.light:
|
||||
@@ -67,7 +75,7 @@ class SettingsProvider extends ChangeNotifier {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
final themeIndex = prefs.getInt('theme_option') ?? 0;
|
||||
_themeOption = ThemeOption.values[themeIndex];
|
||||
|
||||
|
||||
// Load time range settings
|
||||
_morningStart = prefs.getInt('morning_start') ?? 5;
|
||||
_morningEnd = prefs.getInt('morning_end') ?? 10;
|
||||
@@ -77,19 +85,23 @@ class SettingsProvider extends ChangeNotifier {
|
||||
_eveningEnd = prefs.getInt('evening_end') ?? 22;
|
||||
_nightStart = prefs.getInt('night_start') ?? 23;
|
||||
_nightEnd = prefs.getInt('night_end') ?? 4;
|
||||
|
||||
|
||||
// Load persistent reminder settings
|
||||
_persistentReminders = prefs.getBool('persistent_reminders') ?? true;
|
||||
_reminderRetryInterval = prefs.getInt('reminder_retry_interval') ?? 5;
|
||||
_maxRetryAttempts = prefs.getInt('max_retry_attempts') ?? 3;
|
||||
|
||||
|
||||
// Load auto-sync settings
|
||||
_autoSyncEnabled = prefs.getBool('auto_sync_enabled') ?? false;
|
||||
_autoSyncDebounceSeconds = prefs.getInt('auto_sync_debounce_seconds') ?? 30;
|
||||
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> setThemeOption(ThemeOption option) async {
|
||||
_themeOption = option;
|
||||
notifyListeners();
|
||||
|
||||
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
await prefs.setInt('theme_option', option.index);
|
||||
}
|
||||
@@ -146,14 +158,14 @@ class SettingsProvider extends ChangeNotifier {
|
||||
if (morningStart > morningEnd) return false;
|
||||
if (afternoonStart > afternoonEnd) return false;
|
||||
if (eveningStart > eveningEnd) return false;
|
||||
|
||||
|
||||
// Night can wrap around midnight, so we allow nightStart > nightEnd
|
||||
|
||||
|
||||
// Check for overlaps in sequential periods
|
||||
if (morningEnd >= afternoonStart) return false;
|
||||
if (afternoonEnd >= eveningStart) return false;
|
||||
if (eveningEnd >= nightStart) return false;
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -174,7 +186,7 @@ class SettingsProvider extends ChangeNotifier {
|
||||
int afternoonCount = 0;
|
||||
int eveningCount = 0;
|
||||
int nightCount = 0;
|
||||
|
||||
|
||||
for (final hour in hours) {
|
||||
if (hour >= _morningStart && hour <= _morningEnd) {
|
||||
morningCount++;
|
||||
@@ -186,13 +198,13 @@ class SettingsProvider extends ChangeNotifier {
|
||||
nightCount++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// If supplement is taken throughout the day (has times in multiple periods)
|
||||
final periodsCount = (morningCount > 0 ? 1 : 0) +
|
||||
(afternoonCount > 0 ? 1 : 0) +
|
||||
(eveningCount > 0 ? 1 : 0) +
|
||||
final periodsCount = (morningCount > 0 ? 1 : 0) +
|
||||
(afternoonCount > 0 ? 1 : 0) +
|
||||
(eveningCount > 0 ? 1 : 0) +
|
||||
(nightCount > 0 ? 1 : 0);
|
||||
|
||||
|
||||
if (periodsCount >= 2) {
|
||||
// Categorize based on the earliest reminder time for consistency
|
||||
final earliestHour = hours.reduce((a, b) => a < b ? a : b);
|
||||
@@ -206,7 +218,7 @@ class SettingsProvider extends ChangeNotifier {
|
||||
return 'night';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// If all times are in one period, categorize accordingly
|
||||
if (morningCount > 0) {
|
||||
return 'morning';
|
||||
@@ -236,7 +248,7 @@ class SettingsProvider extends ChangeNotifier {
|
||||
Future<void> setPersistentReminders(bool enabled) async {
|
||||
_persistentReminders = enabled;
|
||||
notifyListeners();
|
||||
|
||||
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
await prefs.setBool('persistent_reminders', enabled);
|
||||
}
|
||||
@@ -244,7 +256,7 @@ class SettingsProvider extends ChangeNotifier {
|
||||
Future<void> setReminderRetryInterval(int minutes) async {
|
||||
_reminderRetryInterval = minutes;
|
||||
notifyListeners();
|
||||
|
||||
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
await prefs.setInt('reminder_retry_interval', minutes);
|
||||
}
|
||||
@@ -252,8 +264,25 @@ class SettingsProvider extends ChangeNotifier {
|
||||
Future<void> setMaxRetryAttempts(int attempts) async {
|
||||
_maxRetryAttempts = attempts;
|
||||
notifyListeners();
|
||||
|
||||
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
await prefs.setInt('max_retry_attempts', attempts);
|
||||
}
|
||||
|
||||
// Auto-sync setters
|
||||
Future<void> setAutoSyncEnabled(bool enabled) async {
|
||||
_autoSyncEnabled = enabled;
|
||||
notifyListeners();
|
||||
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
await prefs.setBool('auto_sync_enabled', enabled);
|
||||
}
|
||||
|
||||
Future<void> setAutoSyncDebounceSeconds(int seconds) async {
|
||||
_autoSyncDebounceSeconds = seconds;
|
||||
notifyListeners();
|
||||
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
await prefs.setInt('auto_sync_debounce_seconds', seconds);
|
||||
}
|
||||
}
|
||||
|
@@ -1,7 +1,8 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../services/database_sync_service.dart';
|
||||
import '../services/auto_sync_service.dart';
|
||||
import 'settings_provider.dart';
|
||||
|
||||
class SimpleSyncProvider with ChangeNotifier {
|
||||
final DatabaseSyncService _syncService = DatabaseSyncService();
|
||||
@@ -9,6 +10,12 @@ class SimpleSyncProvider with ChangeNotifier {
|
||||
// Callback for UI refresh after sync
|
||||
VoidCallback? _onSyncCompleteCallback;
|
||||
|
||||
// Auto-sync service
|
||||
AutoSyncService? _autoSyncService;
|
||||
|
||||
// Track if current sync is auto-triggered
|
||||
bool _isAutoSync = false;
|
||||
|
||||
// Getters
|
||||
SyncStatus get status => _syncService.status;
|
||||
String? get lastError => _syncService.lastError;
|
||||
@@ -17,6 +24,14 @@ class SimpleSyncProvider with ChangeNotifier {
|
||||
bool get isSyncing => status == SyncStatus.downloading ||
|
||||
status == SyncStatus.merging ||
|
||||
status == SyncStatus.uploading;
|
||||
bool get isAutoSync => _isAutoSync;
|
||||
AutoSyncService? get autoSyncService => _autoSyncService;
|
||||
|
||||
// Auto-sync error handling getters
|
||||
bool get isAutoSyncDisabledDueToErrors => _autoSyncService?.isAutoDisabledDueToErrors ?? false;
|
||||
int get autoSyncConsecutiveFailures => _autoSyncService?.consecutiveFailures ?? 0;
|
||||
String? get autoSyncLastError => _autoSyncService?.lastErrorMessage;
|
||||
bool get hasAutoSyncScheduledRetry => _autoSyncService?.hasScheduledRetry ?? false;
|
||||
|
||||
// Configuration getters
|
||||
String? get serverUrl => _syncService.serverUrl;
|
||||
@@ -43,6 +58,23 @@ class SimpleSyncProvider with ChangeNotifier {
|
||||
_onSyncCompleteCallback = callback;
|
||||
}
|
||||
|
||||
/// Initialize auto-sync service with settings provider
|
||||
void initializeAutoSync(SettingsProvider settingsProvider) {
|
||||
_autoSyncService = AutoSyncService(
|
||||
syncProvider: this,
|
||||
settingsProvider: settingsProvider,
|
||||
);
|
||||
|
||||
if (kDebugMode) {
|
||||
print('SimpleSyncProvider: Auto-sync service initialized');
|
||||
}
|
||||
}
|
||||
|
||||
/// Triggers auto-sync if enabled and configured
|
||||
void triggerAutoSyncIfEnabled() {
|
||||
_autoSyncService?.triggerAutoSync();
|
||||
}
|
||||
|
||||
Future<void> _loadConfiguration() async {
|
||||
await _syncService.loadSavedConfiguration();
|
||||
notifyListeners(); // Notify UI that configuration might be available
|
||||
@@ -67,11 +99,14 @@ class SimpleSyncProvider with ChangeNotifier {
|
||||
return await _syncService.testConnection();
|
||||
}
|
||||
|
||||
Future<void> syncDatabase() async {
|
||||
Future<void> syncDatabase({bool isAutoSync = false}) async {
|
||||
if (!isConfigured) {
|
||||
throw Exception('Sync not configured');
|
||||
}
|
||||
|
||||
_isAutoSync = isAutoSync;
|
||||
notifyListeners();
|
||||
|
||||
try {
|
||||
await _syncService.syncDatabase();
|
||||
} catch (e) {
|
||||
@@ -79,6 +114,9 @@ class SimpleSyncProvider with ChangeNotifier {
|
||||
print('SupplementsLog: Sync failed in provider: $e');
|
||||
}
|
||||
rethrow;
|
||||
} finally {
|
||||
_isAutoSync = false;
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,20 +125,46 @@ class SimpleSyncProvider with ChangeNotifier {
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
/// Resets auto-sync error state and re-enables auto-sync if it was disabled
|
||||
void resetAutoSyncErrors() {
|
||||
_autoSyncService?.resetErrorState();
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
String getStatusText() {
|
||||
final syncType = _isAutoSync ? 'Auto-sync' : 'Sync';
|
||||
|
||||
// Check for auto-sync specific errors first
|
||||
if (isAutoSyncDisabledDueToErrors) {
|
||||
return 'Auto-sync disabled due to repeated failures. ${autoSyncLastError ?? 'Check sync settings.'}';
|
||||
}
|
||||
|
||||
switch (status) {
|
||||
case SyncStatus.idle:
|
||||
if (hasAutoSyncScheduledRetry) {
|
||||
return 'Auto-sync will retry shortly...';
|
||||
}
|
||||
return 'Ready to sync';
|
||||
case SyncStatus.downloading:
|
||||
return 'Downloading remote database...';
|
||||
return '$syncType: Downloading remote database...';
|
||||
case SyncStatus.merging:
|
||||
return 'Merging databases...';
|
||||
return '$syncType: Merging databases...';
|
||||
case SyncStatus.uploading:
|
||||
return 'Uploading database...';
|
||||
return '$syncType: Uploading database...';
|
||||
case SyncStatus.completed:
|
||||
return 'Sync completed successfully';
|
||||
return '$syncType completed successfully';
|
||||
case SyncStatus.error:
|
||||
return 'Sync failed: ${lastError ?? 'Unknown error'}';
|
||||
// For auto-sync errors, show more specific messages
|
||||
if (_isAutoSync && autoSyncLastError != null) {
|
||||
return 'Auto-sync failed: $autoSyncLastError';
|
||||
}
|
||||
return '$syncType failed: ${lastError ?? 'Unknown error'}';
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_autoSyncService?.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user