Implementado:

No se puede marcar “vista” sin revelar la palabra antes.
Se puede volver a ver la palabra durante debate/votación/resultado.
Notas online privadas por partida y jugador.
Tests añadidos para notas scoped.
Ajusté roomId en el payload de inicio para que las notas no se mezclen entre partidas.
This commit is contained in:
2026-05-05 21:49:40 +02:00
parent 1abdeb2f56
commit 6e5e423ab4
12 changed files with 802 additions and 75 deletions

View File

@@ -794,6 +794,7 @@ class ServicioNearby extends ChangeNotifier {
'esImpostor': esImpostor,
'categoria': categoria,
'numJugadores': _jugadores.length + 1,
'roomId': _roomId,
},
),
);
@@ -819,6 +820,7 @@ class ServicioNearby extends ChangeNotifier {
if (endpointId == null) continue;
final datos = payload.toJson();
datos['jugadoresTodos'] = jugadoresTodos;
datos['roomId'] = _roomId;
await enviarMensaje(
endpointId,
MensajeP2P(tipo: TipoMensaje.partidaInicio, datos: datos),

View File

@@ -1,42 +1,94 @@
import 'dart:convert';
import 'package:shared_preferences/shared_preferences.dart';
/// Servicio para persistir las notas de los jugadores localmente
/// Servicio para persistir las notas de los jugadores localmente.
class ServicioNotas {
static const _clavePrefix = 'notas_';
static const _clavePartidaPrefix = 'notas_partida_';
/// Guarda las notas de un jugador para una partida
/// Guarda las notas de un jugador para una partida local/legacy.
static Future<void> guardarNotas(
String jugadorId,
Map<String, String> notas,
String notaLibre,
) async {
final prefs = await SharedPreferences.getInstance();
final datos = {
await prefs.setString(
'$_clavePrefix$jugadorId',
json.encode(_serializar(notas, notaLibre)),
);
}
/// Carga las notas de un jugador en modo local/legacy.
static Future<Map<String, dynamic>> cargarNotas(String jugadorId) async {
final prefs = await SharedPreferences.getInstance();
return _decodificar(prefs.getString('$_clavePrefix$jugadorId'));
}
/// Guarda notas privadas scoped por partida y jugador autor.
///
/// Esto evita que una partida online contamine otra aunque se reutilicen
/// nombres o ids visibles de jugador.
static Future<void> guardarNotasPartida({
required String partidaId,
required String autorJugadorId,
required Map<String, String> notasPorJugador,
required String notaLibre,
}) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setString(
_claveNotasPartida(partidaId, autorJugadorId),
json.encode(_serializar(notasPorJugador, notaLibre)),
);
}
/// Carga notas privadas scoped por partida y jugador autor.
static Future<Map<String, dynamic>> cargarNotasPartida({
required String partidaId,
required String autorJugadorId,
}) async {
final prefs = await SharedPreferences.getInstance();
return _decodificar(
prefs.getString(_claveNotasPartida(partidaId, autorJugadorId)),
);
}
static String _claveNotasPartida(String partidaId, String autorJugadorId) {
return '$_clavePartidaPrefix${_normalizarClave(partidaId)}_${_normalizarClave(autorJugadorId)}';
}
static String _normalizarClave(String valor) {
return base64Url.encode(utf8.encode(valor));
}
static Map<String, Object> _serializar(
Map<String, String> notas,
String notaLibre,
) {
return {
'notas': notas,
'notaLibre': notaLibre,
};
await prefs.setString('$_clavePrefix$jugadorId', json.encode(datos));
}
/// Carga las notas de un jugador
static Future<Map<String, dynamic>> cargarNotas(String jugadorId) async {
final prefs = await SharedPreferences.getInstance();
final str = prefs.getString('$_clavePrefix$jugadorId');
static Map<String, dynamic> _decodificar(String? str) {
if (str == null) {
return {'notas': <String, String>{}, 'notaLibre': ''};
}
final datos = json.decode(str) as Map<String, dynamic>;
return {
'notas': Map<String, String>.from(datos['notas'] ?? {}),
'notaLibre': datos['notaLibre'] ?? '',
'notaLibre': datos['notaLibre'] as String? ?? '',
};
}
/// Limpia todas las notas (al iniciar nueva partida)
/// Limpia todas las notas (al iniciar nueva partida local o reset manual).
static Future<void> limpiarNotas() async {
final prefs = await SharedPreferences.getInstance();
final claves = prefs.getKeys().where((k) => k.startsWith(_clavePrefix));
final claves = prefs
.getKeys()
.where((k) => k.startsWith(_clavePrefix))
.toList();
for (final clave in claves) {
await prefs.remove(clave);
}