import 'dart:convert'; import 'package:flutter/foundation.dart'; import 'package:shared_preferences/shared_preferences.dart'; import '../modelos/gamificacion_usuario.dart'; class PerfilUsuario { final String nombre; final String nick; final String avatarAsset; const PerfilUsuario({ required this.nombre, required this.nick, required this.avatarAsset, }); PerfilUsuario copiar({String? nombre, String? nick, String? avatarAsset}) { return PerfilUsuario( nombre: nombre ?? this.nombre, nick: nick ?? this.nick, avatarAsset: avatarAsset ?? this.avatarAsset, ); } } class ServicioPerfilUsuario extends ChangeNotifier { static const _claveNombre = 'perfil.nombre'; static const _claveNick = 'perfil.nick'; static const _claveAvatar = 'perfil.avatar'; static const _claveEstadisticas = 'perfil.estadisticas'; static const avatares = [ 'assets/avatars/avatar_01.png', 'assets/avatars/avatar_02.png', 'assets/avatars/avatar_03.png', 'assets/avatars/avatar_04.png', 'assets/avatars/avatar_05.png', 'assets/avatars/avatar_06.png', 'assets/avatars/avatar_07.png', 'assets/avatars/avatar_08.png', 'assets/avatars/avatar_09.png', 'assets/avatars/avatar_10.png', 'assets/avatars/avatar_11.png', 'assets/avatars/avatar_12.png', 'assets/avatars/avatar_13.png', 'assets/avatars/avatar_14.png', 'assets/avatars/avatar_15.png', 'assets/avatars/avatar_16.png', 'assets/avatars/avatar_17.png', 'assets/avatars/avatar_18.png', 'assets/avatars/avatar_19.png', 'assets/avatars/avatar_20.png', 'assets/avatars/avatar_21.png', 'assets/avatars/avatar_22.png', 'assets/avatars/avatar_23.png', 'assets/avatars/avatar_24.png', 'assets/avatars/avatar_25.png', 'assets/avatars/avatar_26.png', 'assets/avatars/avatar_27.png', 'assets/avatars/avatar_28.png', 'assets/avatars/avatar_29.png', 'assets/avatars/avatar_30.png', 'assets/avatars/avatar_79.png', 'assets/avatars/avatar_80.png', 'assets/avatars/avatar_81.png', 'assets/avatars/avatar_82.png', 'assets/avatars/avatar_83.png', 'assets/avatars/avatar_84.png', 'assets/avatars/avatar_31.png', 'assets/avatars/avatar_32.png', 'assets/avatars/avatar_33.png', 'assets/avatars/avatar_34.png', 'assets/avatars/avatar_35.png', 'assets/avatars/avatar_36.png', 'assets/avatars/avatar_37.png', 'assets/avatars/avatar_38.png', 'assets/avatars/avatar_39.png', 'assets/avatars/avatar_40.png', 'assets/avatars/avatar_41.png', 'assets/avatars/avatar_42.png', 'assets/avatars/avatar_43.png', 'assets/avatars/avatar_44.png', 'assets/avatars/avatar_45.png', 'assets/avatars/avatar_46.png', 'assets/avatars/avatar_47.png', 'assets/avatars/avatar_48.png', 'assets/avatars/avatar_49.png', 'assets/avatars/avatar_50.png', 'assets/avatars/avatar_51.png', 'assets/avatars/avatar_52.png', 'assets/avatars/avatar_53.png', 'assets/avatars/avatar_54.png', 'assets/avatars/avatar_55.png', 'assets/avatars/avatar_56.png', 'assets/avatars/avatar_57.png', 'assets/avatars/avatar_58.png', 'assets/avatars/avatar_59.png', 'assets/avatars/avatar_60.png', 'assets/avatars/avatar_61.png', 'assets/avatars/avatar_62.png', 'assets/avatars/avatar_63.png', 'assets/avatars/avatar_64.png', 'assets/avatars/avatar_65.png', 'assets/avatars/avatar_66.png', 'assets/avatars/avatar_67.png', 'assets/avatars/avatar_68.png', 'assets/avatars/avatar_69.png', 'assets/avatars/avatar_70.png', 'assets/avatars/avatar_71.png', 'assets/avatars/avatar_72.png', 'assets/avatars/avatar_73.png', 'assets/avatars/avatar_74.png', 'assets/avatars/avatar_75.png', 'assets/avatars/avatar_76.png', 'assets/avatars/avatar_77.png', 'assets/avatars/avatar_78.png', ]; PerfilUsuario _perfil = const PerfilUsuario( nombre: 'Jugador', nick: 'farolero', avatarAsset: 'assets/avatars/avatar_01.png', ); EstadisticasPerfilUsuario _estadisticas = const EstadisticasPerfilUsuario(); bool _cargado = false; PerfilUsuario get perfil => _perfil; EstadisticasPerfilUsuario get estadisticas => _estadisticas; ResumenGamificacionUsuario get resumenGamificacion => _estadisticas.resumen; bool get cargado => _cargado; Future cargar() async { final prefs = await SharedPreferences.getInstance(); _perfil = PerfilUsuario( nombre: prefs.getString(_claveNombre) ?? _perfil.nombre, nick: prefs.getString(_claveNick) ?? _perfil.nick, avatarAsset: prefs.getString(_claveAvatar) ?? _perfil.avatarAsset, ); final estadisticasJson = prefs.getString(_claveEstadisticas); if (estadisticasJson != null) { try { _estadisticas = EstadisticasPerfilUsuario.fromJson( json.decode(estadisticasJson) as Map, ); } catch (_) { _estadisticas = const EstadisticasPerfilUsuario(); } } _cargado = true; notifyListeners(); } Future guardar({ required String nombre, required String nick, required String avatarAsset, }) async { final nombreLimpio = nombre.trim().isEmpty ? 'Jugador' : nombre.trim(); final nickLimpio = nick.trim().isEmpty ? 'farolero' : nick.trim(); final avatarSeguro = avatares.contains(avatarAsset) ? avatarAsset : avatares.first; _perfil = PerfilUsuario( nombre: nombreLimpio, nick: nickLimpio, avatarAsset: avatarSeguro, ); final prefs = await SharedPreferences.getInstance(); await prefs.setString(_claveNombre, _perfil.nombre); await prefs.setString(_claveNick, _perfil.nick); await prefs.setString(_claveAvatar, _perfil.avatarAsset); notifyListeners(); } Future registrarPartidaCompletada({ required bool victoria, bool comoImpostor = false, bool victoriaComoImpostor = false, DateTime? fecha, }) async { final antes = _estadisticas; final despues = antes.registrarPartida( victoria: victoria, comoImpostor: comoImpostor, victoriaComoImpostor: victoriaComoImpostor, fecha: fecha, ); final medallasPrevias = antes.medallas.toSet(); final nuevasMedallas = despues.medallas .where((id) => !medallasPrevias.contains(id)) .toList(growable: false); _estadisticas = despues; final prefs = await SharedPreferences.getInstance(); await prefs.setString(_claveEstadisticas, json.encode(despues.toJson())); notifyListeners(); return ProgresoGamificacionUsuario( antes: antes, despues: despues, nuevasMedallas: nuevasMedallas, ); } }