feat(02-01): create SettingsProvider for theme and unit state

- Created lib/providers/settings_provider.dart
- Extends ChangeNotifier for reactive state management
- Constructor accepts pre-initialized SharedPreferences instance
- Loads theme index and speed unit synchronously from SharedPreferences
- cycleTheme() and cycleUnit() methods with haptic feedback
- Persists settings to SharedPreferences on every change
- Both cycle methods call notifyListeners() for reactive UI updates
- No notifyListeners() in constructor (runs before first build)
This commit is contained in:
Mikkeli Matlock
2026-02-10 22:04:00 +09:00
parent f458b62eea
commit 1961651151
+50
View File
@@ -0,0 +1,50 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../config/speed_unit.dart';
import '../config/color_themes.dart';
import '../services/logger.dart';
class SettingsProvider extends ChangeNotifier {
final SharedPreferences _prefs;
int _currentThemeIndex = 0;
SpeedUnit _currentUnit = SpeedUnit.kmh;
// Getters for read access
int get currentThemeIndex => _currentThemeIndex;
SpeedUnit get currentUnit => _currentUnit;
ColorTheme get currentTheme => ColorThemes.getTheme(_currentThemeIndex);
/// Constructor loads settings synchronously from pre-initialized SharedPreferences.
/// SharedPreferences MUST be initialized before constructing this provider.
SettingsProvider(this._prefs) {
_loadSettings();
Logger.info('Settings loaded: theme=$_currentThemeIndex, unit=${_currentUnit.label}', 'SettingsProvider');
}
void _loadSettings() {
_currentThemeIndex = _prefs.getInt('themeIndex') ?? 0;
final unitIndex = _prefs.getInt('unitIndex') ?? 0;
_currentUnit = SpeedUnit.values[unitIndex.clamp(0, SpeedUnit.values.length - 1)];
// No notifyListeners() — constructor runs before first build
}
/// Cycle to next theme with haptic feedback and persistence
void cycleTheme() {
HapticFeedback.lightImpact();
_currentThemeIndex = ColorThemes.getNextThemeIndex(_currentThemeIndex);
_prefs.setInt('themeIndex', _currentThemeIndex);
Logger.debug('Theme cycled to index $_currentThemeIndex', 'SettingsProvider');
notifyListeners();
}
/// Cycle to next speed unit with haptic feedback and persistence
void cycleUnit() {
HapticFeedback.lightImpact();
_currentUnit = _currentUnit.next;
_prefs.setInt('unitIndex', _currentUnit.index);
Logger.debug('Unit cycled to ${_currentUnit.label}', 'SettingsProvider');
notifyListeners();
}
}