mirror of
https://github.com/vleeuwenmenno/supplements.git
synced 2025-09-11 18:29:12 +02:00
325 lines
10 KiB
Dart
325 lines
10 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:shared_preferences/shared_preferences.dart';
|
|
|
|
enum ThemeOption {
|
|
system,
|
|
light,
|
|
dark,
|
|
}
|
|
|
|
class SettingsProvider extends ChangeNotifier {
|
|
ThemeOption _themeOption = ThemeOption.system;
|
|
|
|
// Time range settings (stored as hours, 0-23)
|
|
int _morningStart = 5;
|
|
int _morningEnd = 10;
|
|
int _afternoonStart = 11;
|
|
int _afternoonEnd = 16;
|
|
int _eveningStart = 17;
|
|
int _eveningEnd = 22;
|
|
int _nightStart = 23;
|
|
int _nightEnd = 4;
|
|
|
|
// Notifications
|
|
int _snoozeMinutes = 10;
|
|
|
|
// Notification retry settings
|
|
bool _notificationRetryEnabled = true;
|
|
int _notificationRetryCount = 3;
|
|
int _notificationRetryDelayMinutes = 5;
|
|
|
|
// Auto-sync settings
|
|
bool _autoSyncEnabled = false;
|
|
int _autoSyncDebounceSeconds = 5;
|
|
|
|
ThemeOption get themeOption => _themeOption;
|
|
|
|
// Time range getters
|
|
int get morningStart => _morningStart;
|
|
int get morningEnd => _morningEnd;
|
|
int get afternoonStart => _afternoonStart;
|
|
int get afternoonEnd => _afternoonEnd;
|
|
int get eveningStart => _eveningStart;
|
|
int get eveningEnd => _eveningEnd;
|
|
int get nightStart => _nightStart;
|
|
int get nightEnd => _nightEnd;
|
|
|
|
// Notifications
|
|
int get snoozeMinutes => _snoozeMinutes;
|
|
|
|
// Notification retry getters
|
|
bool get notificationRetryEnabled => _notificationRetryEnabled;
|
|
int get notificationRetryCount => _notificationRetryCount;
|
|
int get notificationRetryDelayMinutes => _notificationRetryDelayMinutes;
|
|
|
|
// 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:
|
|
return ThemeMode.light;
|
|
case ThemeOption.dark:
|
|
return ThemeMode.dark;
|
|
case ThemeOption.system:
|
|
return ThemeMode.system;
|
|
}
|
|
}
|
|
|
|
Future<void> initialize() async {
|
|
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;
|
|
_afternoonStart = prefs.getInt('afternoon_start') ?? 11;
|
|
_afternoonEnd = prefs.getInt('afternoon_end') ?? 16;
|
|
_eveningStart = prefs.getInt('evening_start') ?? 17;
|
|
_eveningEnd = prefs.getInt('evening_end') ?? 22;
|
|
_nightStart = prefs.getInt('night_start') ?? 23;
|
|
_nightEnd = prefs.getInt('night_end') ?? 4;
|
|
|
|
// Load snooze setting
|
|
_snoozeMinutes = prefs.getInt('snooze_minutes') ?? 10;
|
|
|
|
// Load notification retry settings
|
|
_notificationRetryEnabled = prefs.getBool('notification_retry_enabled') ?? true;
|
|
_notificationRetryCount = prefs.getInt('notification_retry_count') ?? 3;
|
|
_notificationRetryDelayMinutes = prefs.getInt('notification_retry_delay_minutes') ?? 5;
|
|
|
|
// 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);
|
|
}
|
|
|
|
Future<void> setDateOfBirthAndGender(DateTime dateOfBirth, String gender) async {
|
|
notifyListeners();
|
|
|
|
final prefs = await SharedPreferences.getInstance();
|
|
await prefs.setString('date_of_birth', dateOfBirth.toIso8601String());
|
|
await prefs.setString('gender', gender);
|
|
}
|
|
|
|
Future<void> setTimeRanges({
|
|
required int morningStart,
|
|
required int morningEnd,
|
|
required int afternoonStart,
|
|
required int afternoonEnd,
|
|
required int eveningStart,
|
|
required int eveningEnd,
|
|
required int nightStart,
|
|
required int nightEnd,
|
|
}) async {
|
|
// Validate ranges don't overlap (simplified validation)
|
|
if (!_areTimeRangesValid(
|
|
morningStart, morningEnd,
|
|
afternoonStart, afternoonEnd,
|
|
eveningStart, eveningEnd,
|
|
nightStart, nightEnd,
|
|
)) {
|
|
throw ArgumentError('Time ranges overlap or are invalid');
|
|
}
|
|
|
|
_morningStart = morningStart;
|
|
_morningEnd = morningEnd;
|
|
_afternoonStart = afternoonStart;
|
|
_afternoonEnd = afternoonEnd;
|
|
_eveningStart = eveningStart;
|
|
_eveningEnd = eveningEnd;
|
|
_nightStart = nightStart;
|
|
_nightEnd = nightEnd;
|
|
|
|
notifyListeners();
|
|
|
|
final prefs = await SharedPreferences.getInstance();
|
|
await prefs.setInt('morning_start', morningStart);
|
|
await prefs.setInt('morning_end', morningEnd);
|
|
await prefs.setInt('afternoon_start', afternoonStart);
|
|
await prefs.setInt('afternoon_end', afternoonEnd);
|
|
await prefs.setInt('evening_start', eveningStart);
|
|
await prefs.setInt('evening_end', eveningEnd);
|
|
await prefs.setInt('night_start', nightStart);
|
|
await prefs.setInt('night_end', nightEnd);
|
|
}
|
|
|
|
bool _areTimeRangesValid(
|
|
int morningStart, int morningEnd,
|
|
int afternoonStart, int afternoonEnd,
|
|
int eveningStart, int eveningEnd,
|
|
int nightStart, int nightEnd,
|
|
) {
|
|
// Basic validation - ensure start < end for non-wrapping periods
|
|
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;
|
|
}
|
|
|
|
// Method to determine time category based on current settings
|
|
String determineTimeCategory(List<String> reminderTimes) {
|
|
if (reminderTimes.isEmpty) {
|
|
return 'anytime';
|
|
}
|
|
|
|
// Convert reminder times to hours for categorization
|
|
final hours = reminderTimes.map((time) {
|
|
final parts = time.split(':');
|
|
return int.tryParse(parts[0]) ?? 12;
|
|
}).toList();
|
|
|
|
// Count how many times fall into each category
|
|
int morningCount = 0;
|
|
int afternoonCount = 0;
|
|
int eveningCount = 0;
|
|
int nightCount = 0;
|
|
|
|
for (final hour in hours) {
|
|
if (hour >= _morningStart && hour <= _morningEnd) {
|
|
morningCount++;
|
|
} else if (hour >= _afternoonStart && hour <= _afternoonEnd) {
|
|
afternoonCount++;
|
|
} else if (hour >= _eveningStart && hour <= _eveningEnd) {
|
|
eveningCount++;
|
|
} else if (_isInNightRange(hour)) {
|
|
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) +
|
|
(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);
|
|
if (earliestHour >= _morningStart && earliestHour <= _morningEnd) {
|
|
return 'morning';
|
|
} else if (earliestHour >= _afternoonStart && earliestHour <= _afternoonEnd) {
|
|
return 'afternoon';
|
|
} else if (earliestHour >= _eveningStart && earliestHour <= _eveningEnd) {
|
|
return 'evening';
|
|
} else if (_isInNightRange(earliestHour)) {
|
|
return 'night';
|
|
}
|
|
}
|
|
|
|
// If all times are in one period, categorize accordingly
|
|
if (morningCount > 0) {
|
|
return 'morning';
|
|
} else if (afternoonCount > 0) {
|
|
return 'afternoon';
|
|
} else if (eveningCount > 0) {
|
|
return 'evening';
|
|
} else if (nightCount > 0) {
|
|
return 'night';
|
|
} else {
|
|
return 'anytime';
|
|
}
|
|
}
|
|
|
|
bool _isInNightRange(int hour) {
|
|
// Night range can wrap around midnight
|
|
if (_nightStart <= _nightEnd) {
|
|
// Normal range (doesn't wrap around midnight)
|
|
return hour >= _nightStart && hour <= _nightEnd;
|
|
} else {
|
|
// Wrapping range (e.g., 23:00 to 4:00)
|
|
return hour >= _nightStart || hour <= _nightEnd;
|
|
}
|
|
}
|
|
|
|
// Notifications setters
|
|
Future<void> setSnoozeMinutes(int minutes) async {
|
|
const allowed = [5, 10, 15, 20];
|
|
if (!allowed.contains(minutes)) {
|
|
throw ArgumentError('Snooze minutes must be one of ${allowed.join(", ")}');
|
|
}
|
|
_snoozeMinutes = minutes;
|
|
notifyListeners();
|
|
|
|
final prefs = await SharedPreferences.getInstance();
|
|
await prefs.setInt('snooze_minutes', minutes);
|
|
}
|
|
|
|
Future<void> setNotificationRetryEnabled(bool enabled) async {
|
|
_notificationRetryEnabled = enabled;
|
|
notifyListeners();
|
|
|
|
final prefs = await SharedPreferences.getInstance();
|
|
await prefs.setBool('notification_retry_enabled', enabled);
|
|
}
|
|
|
|
Future<void> setNotificationRetryCount(int count) async {
|
|
if (count < 0 || count > 10) {
|
|
throw ArgumentError('Retry count must be between 0 and 10');
|
|
}
|
|
_notificationRetryCount = count;
|
|
notifyListeners();
|
|
|
|
final prefs = await SharedPreferences.getInstance();
|
|
await prefs.setInt('notification_retry_count', count);
|
|
}
|
|
|
|
Future<void> setNotificationRetryDelayMinutes(int minutes) async {
|
|
const allowed = [1, 2, 3, 5, 10, 15, 20, 30];
|
|
if (!allowed.contains(minutes)) {
|
|
throw ArgumentError('Retry delay must be one of ${allowed.join(", ")} minutes');
|
|
}
|
|
_notificationRetryDelayMinutes = minutes;
|
|
notifyListeners();
|
|
|
|
final prefs = await SharedPreferences.getInstance();
|
|
await prefs.setInt('notification_retry_delay_minutes', minutes);
|
|
}
|
|
|
|
// 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);
|
|
}
|
|
}
|