kz_educa/lib/models/app_models.dart

443 lines
12 KiB
Dart
Executable File

import 'package:cloud_firestore/cloud_firestore.dart';
// -----------------------------------------------------------
// Modelos de Utilizador e Transações
// -----------------------------------------------------------
// ✅ Modelo para o Perfil do Utilizador
class AppUser {
final String uid;
final String username;
final String? email;
final double currentBalance;
final int points;
final List<dynamic> badges;
final String? goal;
final double? monthlyIncome;
final String? profession;
final String? educationLevel;
final String? profileImageUrl; // ✅ URL da imagem de perfil (usado no Firestore)
final String? profileImage; // Caminho local (se necessário, ou ajuste para usar apenas a URL)
AppUser({
required this.uid,
required this.username,
this.email,
this.currentBalance = 0.0,
this.points = 0,
this.badges = const [],
this.goal,
this.monthlyIncome,
this.profession,
this.educationLevel,
this.profileImageUrl,
this.profileImage, // Mantido como String? para compatibilidade, se representar um path
});
// ✅ CORRIGIDO: Lógica de mapeamento para incluir todos os campos,
// e correções nas chaves de profileImageUrl/profileImage
factory AppUser.fromMap(Map<String, dynamic> data) {
return AppUser(
uid: data['uid'] ?? '',
username: data['username'] ?? '',
email: data['email'],
currentBalance: (data['currentBalance'] as num?)?.toDouble() ?? 0.0,
points: (data['points'] as num?)?.toInt() ?? 0,
badges: (data['badges'] as List<dynamic>?) ?? [],
goal: data['goal'],
monthlyIncome: (data['monthlyIncome'] as num?)?.toDouble(),
profession: data['profession'],
educationLevel: data['educationLevel'],
profileImageUrl: data['profileImageUrl'] as String?, // ✅ CHAVE CORRETA
profileImage: data['profileImage'] as String?, // ✅ CHAVE CORRETA
);
}
// ✅ CORRIGIDO: Agora aceita QueryDocumentSnapshot e inclui todos os campos
factory AppUser.fromFirestore(QueryDocumentSnapshot doc) {
final data = doc.data() as Map<String, dynamic>;
return AppUser(
uid: doc.id,
username: data['username'] ?? '',
email: data['email'],
currentBalance: (data['currentBalance'] as num?)?.toDouble() ?? 0.0,
points: (data['points'] as num?)?.toInt() ?? 0,
badges: (data['badges'] as List<dynamic>?) ?? [],
goal: data['goal'],
monthlyIncome: (data['monthlyIncome'] as num?)?.toDouble(),
profession: data['profession'],
educationLevel: data['educationLevel'],
profileImageUrl: data['profileImageUrl'] as String?,
profileImage: data['profileImage'] as String?,
);
}
factory AppUser.newProfile({
required String uid,
required String username,
String? email,
}) {
return AppUser(
uid: uid,
username: username,
email: email,
);
}
Map<String, dynamic> toMap() {
return {
'uid': uid,
'username': username,
'email': email,
'currentBalance': currentBalance,
'points': points,
'badges': badges,
'goal': goal,
'monthlyIncome': monthlyIncome,
'profession': profession,
'educationLevel': educationLevel,
'profileImageUrl': profileImageUrl,
'profileImage': profileImage,
};
}
// ✅ CORRIGIDO: O copyWith agora tem as duas chaves corretas e resolve o erro
AppUser copyWith({
String? uid,
String? username,
String? email,
double? currentBalance,
int? points,
List<dynamic>? badges,
String? goal,
double? monthlyIncome,
String? profession,
String? educationLevel,
String? profileImageUrl,
String? profileImage,
}) {
return AppUser(
uid: uid ?? this.uid,
username: username ?? this.username,
email: email ?? this.email,
currentBalance: currentBalance ?? this.currentBalance,
points: points ?? this.points,
badges: badges ?? this.badges,
goal: goal ?? this.goal,
monthlyIncome: monthlyIncome ?? this.monthlyIncome,
profession: profession ?? this.profession,
educationLevel: educationLevel ?? this.educationLevel,
profileImageUrl: profileImageUrl ?? this.profileImageUrl, // ✅ CORRIGIDO
profileImage: profileImage ?? this.profileImage, // ✅ CORRIGIDO
);
}
}
// -----------------------------------------------------------
// Transações e Orçamentos
// -----------------------------------------------------------
// ✅ Enum para tipos de transação
enum TransactionType {
income,
expense,
}
// ✅ Enum para categorias de transação
enum TransactionCategory {
food, transport, social, education, medical, shopping, others,
salary, invest, business,
}
// ✅ Renomeado de 'Transaction' para 'FinancialTransaction'
class FinancialTransaction {
final String? id;
final String? title;
final double amount;
final TransactionType type;
final TransactionCategory category;
final DateTime date;
final String? note;
FinancialTransaction({
this.id,
this.title,
required this.amount,
required this.type,
required this.category,
required this.date,
this.note,
});
factory FinancialTransaction.fromMap(Map<String, dynamic> data) {
return FinancialTransaction(
id: data['id'],
title: data['title'],
amount: (data['amount'] as num).toDouble(),
type: TransactionType.values.byName(data['type']),
category: TransactionCategory.values.byName(data['category']),
date: (data['date'] as Timestamp).toDate(),
note: data['note'],
);
}
// ✅ CORRIGIDO: Agora aceita QueryDocumentSnapshot para consistência.
factory FinancialTransaction.fromFirestore(QueryDocumentSnapshot doc) {
final data = doc.data() as Map<String, dynamic>;
return FinancialTransaction(
id: doc.id,
title: data['title'],
amount: (data['amount'] as num).toDouble(),
type: TransactionType.values.byName(data['type']),
category: TransactionCategory.values.byName(data['category']),
date: (data['date'] as Timestamp).toDate(),
note: data['note'],
);
}
Map<String, dynamic> toMap() {
return {
'title': title,
'amount': amount,
'type': type.name,
'category': category.name,
'date': Timestamp.fromDate(date),
'note': note,
};
}
}
// Model para Orçamento
class Budget {
final String id;
final String nome;
final double valor;
final double gasto;
final String categoria;
Budget({
required this.id,
required this.nome,
required this.valor,
required this.gasto,
required this.categoria,
});
factory Budget.fromFirestore(QueryDocumentSnapshot doc) {
Map<String, dynamic> data = doc.data() as Map<String, dynamic>;
return Budget(
id: doc.id,
nome: data['nome'] ?? '',
valor: (data['valor'] as num?)?.toDouble() ?? 0.0,
gasto: (data['gasto'] as num?)?.toDouble() ?? 0.0,
categoria: data['categoria'] ?? '',
);
}
}
// -----------------------------------------------------------
// Modelos de Educação e Simulação
// -----------------------------------------------------------
// Model para Simulação de Poupança
class SavingsSimulation {
final String id;
final double valorInicial;
final double depositoMensal;
final double taxaJuros;
final int periodoMeses;
final double resultadoFinal;
final List<dynamic> simulationData;
final String timestamp;
SavingsSimulation({
required this.id,
required this.valorInicial,
required this.depositoMensal,
required this.taxaJuros,
required this.periodoMeses,
required this.resultadoFinal,
required this.simulationData,
required this.timestamp,
});
factory SavingsSimulation.fromFirestore(QueryDocumentSnapshot doc) {
Map<String, dynamic> data = doc.data() as Map<String, dynamic>;
return SavingsSimulation(
id: doc.id,
valorInicial: (data['valorInicial'] as num?)?.toDouble() ?? 0.0,
depositoMensal: (data['depositoMensal'] as num?)?.toDouble() ?? 0.0,
taxaJuros: (data['taxaJuros'] as num?)?.toDouble() ?? 0.0,
periodoMeses: (data['periodoMeses'] as num?)?.toInt() ?? 0,
resultadoFinal: (data['resultadoFinal'] as num?)?.toDouble() ?? 0.0,
simulationData: (data['simulationData'] as List<dynamic>?) ?? [],
timestamp: data['timestamp'] ?? '',
);
}
Map<String, dynamic> toFirestore() {
return {
'valorInicial': valorInicial,
'depositoMensal': depositoMensal,
'taxaJuros': taxaJuros,
'periodoMeses': periodoMeses,
'resultadoFinal': resultadoFinal,
'simulationData': simulationData,
'timestamp': timestamp,
};
}
}
// Model para Desafio Financeiro
class FinancialChallenge {
final String id;
final String nome;
final String meta;
final int points;
FinancialChallenge({required this.id, required this.nome, required this.meta, required this.points});
factory FinancialChallenge.fromFirestore(QueryDocumentSnapshot doc) {
Map<String, dynamic> data = doc.data() as Map<String, dynamic>;
return FinancialChallenge(
id: doc.id,
nome: data['nome'] ?? '',
meta: data['meta'] ?? '',
points: (data['points'] as num?)?.toInt() ?? 0,
);
}
}
// Model para Desafio do Utilizador (aceite)
class UserChallenge {
final String id;
final String challengeId;
final String nome;
final String meta;
final int progresso;
final String acceptedAt;
final String? lastUpdated;
UserChallenge({
required this.id,
required this.challengeId,
required this.nome,
required this.meta,
required this.progresso,
required this.acceptedAt,
this.lastUpdated,
});
factory UserChallenge.fromFirestore(QueryDocumentSnapshot doc) {
Map<String, dynamic> data = doc.data() as Map<String, dynamic>;
return UserChallenge(
id: doc.id,
challengeId: data['challengeId'] ?? '',
nome: data['nome'] ?? '',
meta: data['meta'] ?? '',
progresso: (data['progresso'] as num?)?.toInt() ?? 0,
acceptedAt: data['acceptedAt'] ?? '',
lastUpdated: data['lastUpdated'],
);
}
}
// Model para Aula Rápida
class QuickLesson {
final String id;
final String titulo;
final String duracao;
final String? conteudo;
final String? videoUrl;
final String? bookUrl;
QuickLesson({
required this.id,
required this.titulo,
required this.duracao,
this.conteudo,
this.videoUrl,
this.bookUrl,
});
factory QuickLesson.fromFirestore(QueryDocumentSnapshot doc) {
Map<String, dynamic> data = doc.data() as Map<String, dynamic>;
return QuickLesson(
id: doc.id,
titulo: (data['titulo'] as String?) ?? '',
duracao: (data['duracao'] as String?) ?? '',
conteudo: (data['conteudo'] as String?),
videoUrl: (data['videoUrl'] as String?),
bookUrl: (data['bookUrl'] as String?),
);
}
}
// Model para Aula Concluída pelo Utilizador
class UserCompletedLesson {
final String id; // lessonId
final String completedAt;
UserCompletedLesson({required this.id, required this.completedAt});
factory UserCompletedLesson.fromFirestore(QueryDocumentSnapshot doc) {
Map<String, dynamic> data = doc.data() as Map<String, dynamic>;
return UserCompletedLesson(
id: doc.id,
completedAt: data['completedAt'] ?? '',
);
}
}
// Model para Pergunta de Quiz
class QuizQuestion {
final String id;
final String question;
final List<dynamic> options;
final String answer;
final String explanation;
QuizQuestion({
required this.id,
required this.question,
required this.options,
required this.answer,
required this.explanation,
});
factory QuizQuestion.fromFirestore(QueryDocumentSnapshot doc) {
Map<String, dynamic> data = doc.data() as Map<String, dynamic>;
return QuizQuestion(
id: doc.id,
question: data['question'] ?? '',
options: (data['options'] as List<dynamic>?) ?? [],
answer: data['answer'] ?? '',
explanation: data['explanation'] ?? '',
);
}
}
// Model para Resultado de Quiz do Utilizador
class UserQuizResult {
final String id;
final int score;
final int totalQuestions;
final String timestamp;
UserQuizResult({
required this.id,
required this.score,
required this.totalQuestions,
required this.timestamp,
});
factory UserQuizResult.fromFirestore(QueryDocumentSnapshot doc) {
Map<String, dynamic> data = doc.data() as Map<String, dynamic>;
return UserQuizResult(
id: doc.id,
score: (data['score'] as num?)?.toInt() ?? 0,
totalQuestions: (data['totalQuestions'] as num?)?.toInt() ?? 0,
timestamp: data['timestamp'] ?? '',
);
}
}