Munça da UI de inicio | escovagem semanal adicionada | quantidade de videos assistidos | todos os videos na nuvem | possibilidade de continuar o video de onde parou

This commit is contained in:
Carlos Correia
2026-07-09 15:31:59 +01:00
parent 67b580778a
commit 9fb2840529
14 changed files with 1584 additions and 381 deletions

84
lib/brushing_prefs.dart Normal file
View File

@@ -0,0 +1,84 @@
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 Future<List<DateTime>> _getEntries(String scopeId) async {
final prefs = await SharedPreferences.getInstance();
final raw = prefs.getStringList(_key(_kDatesKey, scopeId)) ?? const [];
return raw.map(DateTime.tryParse).whereType<DateTime>().toList();
}
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;
final prefs = await SharedPreferences.getInstance();
final key = _key(_kDatesKey, scopeId);
final list = prefs.getStringList(key) ?? <String>[];
list.add(DateTime.now().toIso8601String());
await prefs.setStringList(key, list);
}
/// 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).
static Future<int> getWeekCount(String scopeId) async {
final entries = await _getEntries(scopeId);
final now = DateTime.now();
final monday = DateTime(
now.year,
now.month,
now.day,
).subtract(Duration(days: now.weekday - 1));
return entries
.where(
(d) => !DateTime(d.year, d.month, d.day).isBefore(monday),
)
.length;
}
}