103 lines
3.8 KiB
Dart
103 lines
3.8 KiB
Dart
import 'package:shared_preferences/shared_preferences.dart';
|
|
|
|
/// Registo local (por criança) de escovagens e da meta semanal.
|
|
/// Segue o mesmo padrão de [QuizPrefs]: chaves com sufixo `_scopeId`,
|
|
/// guardadas via [SharedPreferences], sem qualquer chamada ao Supabase.
|
|
///
|
|
/// Cada escovagem é guardada com a hora exata (não só a data), para permitir
|
|
/// até [maxPerDay] registos por dia — a criança pode escovar os dentes de
|
|
/// manhã, à tarde e à noite, a qualquer hora.
|
|
class BrushingPrefs {
|
|
static const String _kGoalKey = 'brushing_weekly_goal';
|
|
static const String _kDatesKey = 'brushing_dates';
|
|
static const int maxPerDay = 3;
|
|
static const int defaultWeeklyGoal = maxPerDay * 7;
|
|
|
|
static String _key(String base, String scopeId) => '${base}_$scopeId';
|
|
|
|
static DateTime _currentWeekMonday() {
|
|
final now = DateTime.now();
|
|
return DateTime(
|
|
now.year,
|
|
now.month,
|
|
now.day,
|
|
).subtract(Duration(days: now.weekday - 1));
|
|
}
|
|
|
|
/// Lê as escovagens guardadas e, de caminho, descarta (apaga do
|
|
/// armazenamento) qualquer registo de semanas anteriores — o contador
|
|
/// semanal deve zerar a cada nova semana, não só na exibição mas também
|
|
/// nos dados guardados, para não crescer para sempre.
|
|
static Future<List<DateTime>> _getEntries(String scopeId) async {
|
|
final prefs = await SharedPreferences.getInstance();
|
|
final key = _key(_kDatesKey, scopeId);
|
|
final raw = prefs.getStringList(key) ?? const [];
|
|
final entries = raw.map(DateTime.tryParse).whereType<DateTime>().toList();
|
|
|
|
final monday = _currentWeekMonday();
|
|
final kept = entries
|
|
.where((d) => !DateTime(d.year, d.month, d.day).isBefore(monday))
|
|
.toList();
|
|
if (kept.length != entries.length) {
|
|
await prefs.setStringList(
|
|
key,
|
|
kept.map((d) => d.toIso8601String()).toList(),
|
|
);
|
|
}
|
|
return kept;
|
|
}
|
|
|
|
static Future<int> getWeeklyGoal(String scopeId) async {
|
|
final prefs = await SharedPreferences.getInstance();
|
|
return prefs.getInt(_key(_kGoalKey, scopeId)) ?? defaultWeeklyGoal;
|
|
}
|
|
|
|
static Future<void> setWeeklyGoal(String scopeId, int goal) async {
|
|
final prefs = await SharedPreferences.getInstance();
|
|
await prefs.setInt(_key(_kGoalKey, scopeId), goal);
|
|
}
|
|
|
|
static Future<int> getTodayCount(String scopeId) async {
|
|
final entries = await _getEntries(scopeId);
|
|
final now = DateTime.now();
|
|
return entries
|
|
.where(
|
|
(d) =>
|
|
d.year == now.year && d.month == now.month && d.day == now.day,
|
|
)
|
|
.length;
|
|
}
|
|
|
|
static Future<bool> canLogMore(String scopeId) async {
|
|
return (await getTodayCount(scopeId)) < maxPerDay;
|
|
}
|
|
|
|
/// Regista uma escovagem agora — não faz nada se o limite diário já foi
|
|
/// atingido (chamador deve verificar [canLogMore] antes, se quiser avisar
|
|
/// o utilizador).
|
|
static Future<void> logToday(String scopeId) async {
|
|
if (!(await canLogMore(scopeId))) return;
|
|
// Usa as entradas já podadas (só da semana atual) para não ressuscitar
|
|
// registos de semanas anteriores ao gravar de volta.
|
|
final entries = await _getEntries(scopeId);
|
|
entries.add(DateTime.now());
|
|
final prefs = await SharedPreferences.getInstance();
|
|
await prefs.setStringList(
|
|
_key(_kDatesKey, scopeId),
|
|
entries.map((d) => d.toIso8601String()).toList(),
|
|
);
|
|
}
|
|
|
|
/// Já atingiu o limite diário de [maxPerDay] escovagens hoje?
|
|
static Future<bool> hasReachedDailyLimit(String scopeId) async {
|
|
return (await getTodayCount(scopeId)) >= maxPerDay;
|
|
}
|
|
|
|
/// Conta quantas escovagens foram registadas na semana atual
|
|
/// (segunda-feira a domingo). [_getEntries] já descarta semanas
|
|
/// anteriores, por isso todas as entradas devolvidas já são desta semana.
|
|
static Future<int> getWeekCount(String scopeId) async {
|
|
return (await _getEntries(scopeId)).length;
|
|
}
|
|
}
|