443 lines
12 KiB
Dart
Executable File
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'] ?? '',
|
|
);
|
|
}
|
|
} |