nao esta a funcionar o recycler view

This commit is contained in:
2026-04-21 17:09:44 +01:00
parent c95b3c656e
commit 96d1985998
15 changed files with 317 additions and 183 deletions

View File

@@ -1,2 +1,2 @@
#Thu Mar 12 10:18:44 WET 2026 #Tue Apr 21 15:25:11 WEST 2026
gradle.version=9.3.1 gradle.version=9.4.1

3
.idea/misc.xml generated
View File

@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" /> <component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="21" project-jdk-type="JavaSDK"> <component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="jbr-21" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" /> <output url="file://$PROJECT_DIR$/build/classes" />
</component> </component>
<component name="ProjectType"> <component name="ProjectType">

View File

@@ -109,9 +109,33 @@ public class DetalhePacienteActivity extends AppCompatActivity {
tvNumeroUtente.setText("Nº Utente: " + (numUtente != null ? numUtente : "N/D")); tvNumeroUtente.setText("Nº Utente: " + (numUtente != null ? numUtente : "N/D"));
tvSexo.setText("Sexo: " + (sexo != null ? sexo : "N/D")); tvSexo.setText("Sexo: " + (sexo != null ? sexo : "N/D"));
tvEmail.setText("Email: " + (email != null ? email : "N/D")); tvEmail.setText("Email: " + (email != null ? email : "N/D"));
tvMedicacao.setText(medicacao);
// Buscar medicação real na coleção 'medicamentos'
db.collection("medicamentos")
.whereEqualTo("userId", pacienteId)
.get()
.addOnSuccessListener(querySnapshot -> {
if (querySnapshot != null && !querySnapshot.isEmpty()) {
StringBuilder sb = new StringBuilder();
for (com.google.firebase.firestore.DocumentSnapshot medDoc : querySnapshot.getDocuments()) {
// Tentar campos novos (PT) ou antigos (EN)
String medName = medDoc.getString("nome");
if (medName == null) medName = medDoc.getString("name");
String time = medDoc.getString("hora");
if (time == null) time = medDoc.getString("time");
if (medName != null) {
sb.append("").append(medName);
if (time != null) sb.append(" (").append(time).append(")");
sb.append("\n");
}
}
tvMedicacao.setText(sb.toString().trim());
} else {
tvMedicacao.setText("Nenhuma medicação ativa registada pelo paciente.");
}
});
} else { } else {
Log.d(TAG, "No such document"); Log.d(TAG, "No such document");
Toast.makeText(DetalhePacienteActivity.this, "Paciente não encontrado", Toast.LENGTH_SHORT).show(); Toast.makeText(DetalhePacienteActivity.this, "Paciente não encontrado", Toast.LENGTH_SHORT).show();

View File

@@ -69,13 +69,13 @@ public class EditarPerfilActivity extends AppCompatActivity {
} }
private void carregarDados() { private void carregarDados() {
db.collection("medicos").document(currentUserId).get().addOnSuccessListener(doc -> { db.collection("utilizadores").document(currentUserId).get().addOnSuccessListener(doc -> {
if (doc.exists()) { if (doc.exists()) {
nameEditText.setText(doc.getString("nome")); nameEditText.setText(doc.getString("nome_completo"));
specialtyEditText.setText(doc.getString("especialidade")); specialtyEditText.setText(doc.getString("especialidade"));
emailEditText.setText(doc.getString("email")); emailEditText.setText(doc.getString("email"));
String gender = doc.getString("gender"); String gender = doc.getString("sexo");
if (gender != null) { if (gender != null) {
genderAutoComplete.setText(gender, false); genderAutoComplete.setText(gender, false);
} }
@@ -101,13 +101,17 @@ public class EditarPerfilActivity extends AppCompatActivity {
btnGuardar.setEnabled(false); btnGuardar.setEnabled(false);
Map<String, Object> updates = new HashMap<>(); Map<String, Object> updates = new HashMap<>();
updates.put("nome", name); updates.put("nome_completo", name);
updates.put("especialidade", specialty); updates.put("especialidade", specialty);
updates.put("gender", gender); updates.put("sexo", gender);
db.collection("medicos").document(currentUserId) // Atualizar em 'utilizadores'
db.collection("utilizadores").document(currentUserId)
.update(updates) .update(updates)
.addOnSuccessListener(aVoid -> { .addOnSuccessListener(aVoid -> {
// Também atualizar em 'medicos' para manter sincronizado
db.collection("medicos").document(currentUserId).update(updates);
Toast.makeText(EditarPerfilActivity.this, "Dados atualizados com sucesso!", Toast.LENGTH_SHORT).show(); Toast.makeText(EditarPerfilActivity.this, "Dados atualizados com sucesso!", Toast.LENGTH_SHORT).show();
setResult(RESULT_OK); setResult(RESULT_OK);
finish(); finish();

View File

@@ -30,7 +30,8 @@ import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
public class MainActivity extends AppCompatActivity implements ConsultaAdapter.OnConsultaActionClickListener, ConsultaAdapter.OnConsultaClickListener { public class MainActivity extends AppCompatActivity
implements ConsultaAdapter.OnConsultaActionClickListener, ConsultaAdapter.OnConsultaClickListener {
private View viewAgenda, viewPacientes, viewPerfil, layTop; private View viewAgenda, viewPacientes, viewPerfil, layTop;
@@ -87,6 +88,12 @@ public class MainActivity extends AppCompatActivity implements ConsultaAdapter.O
tvGreetingMain = findViewById(R.id.tv_greeting_main); tvGreetingMain = findViewById(R.id.tv_greeting_main);
// Carregar nome da sessão local para exibir INSTANTANEAMENTE
String cachedName = getSharedPreferences("SessaoMedico", MODE_PRIVATE).getString("nome_medico", "");
if (!cachedName.isEmpty() && tvGreetingMain != null) {
tvGreetingMain.setText("Olá, " + cachedName.split(" ")[0]);
}
// Bind Pacientes // Bind Pacientes
recyclerConsultas = findViewById(R.id.recycler_consultas); recyclerConsultas = findViewById(R.id.recycler_consultas);
textEmptyState = findViewById(R.id.text_empty_state); textEmptyState = findViewById(R.id.text_empty_state);
@@ -185,7 +192,7 @@ public class MainActivity extends AppCompatActivity implements ConsultaAdapter.O
db.collection("utilizadores") db.collection("utilizadores")
.addSnapshotListener((value, error) -> { .addSnapshotListener((value, error) -> {
if (error != null) { if (error != null) {
Toast.makeText(MainActivity.this, "Erro: " + error.getMessage(), Toast.LENGTH_SHORT).show(); Toast.makeText(MainActivity.this, "Erro ao carregar pacientes", Toast.LENGTH_SHORT).show();
return; return;
} }
List<Paciente> pacientesList = new ArrayList<>(); List<Paciente> pacientesList = new ArrayList<>();
@@ -194,13 +201,22 @@ public class MainActivity extends AppCompatActivity implements ConsultaAdapter.O
Paciente p = doc.toObject(Paciente.class); Paciente p = doc.toObject(Paciente.class);
if (p != null) { if (p != null) {
p.setId(doc.getId()); p.setId(doc.getId());
// Garantir que o nome está preenchido // Tenta 'nome_completo' primeiro, depois 'nome'
if (p.getNome() == null) p.setNome(doc.getString("nome")); String nomeVal = doc.getString("nome_completo");
if (p.getEmail() == null) p.setEmail(doc.getString("email")); if (nomeVal == null)
nomeVal = doc.getString("nome");
p.setNome(nomeVal);
if (p.getEmail() == null)
p.setEmail(doc.getString("email"));
// Apenas adiciona se for realmente um paciente ou não tiver tipo definido
String tipo = doc.getString("tipo");
if (tipo == null || tipo.equalsIgnoreCase("paciente")) {
pacientesList.add(p); pacientesList.add(p);
} }
} }
} }
}
if (pacientesList.isEmpty()) { if (pacientesList.isEmpty()) {
textEmptyState.setVisibility(View.VISIBLE); textEmptyState.setVisibility(View.VISIBLE);
@@ -237,29 +253,33 @@ public class MainActivity extends AppCompatActivity implements ConsultaAdapter.O
private void updateConsultaStatus(String consultaId, String newStatus) { private void updateConsultaStatus(String consultaId, String newStatus) {
db.collection("consultas").document(consultaId) db.collection("consultas").document(consultaId)
.update("status", newStatus) .update("status", newStatus)
.addOnSuccessListener(aVoid -> Toast.makeText(this, "Consulta " + newStatus.toLowerCase(), Toast.LENGTH_SHORT).show()) .addOnSuccessListener(
.addOnFailureListener(e -> Toast.makeText(this, "Erro ao atualizar consulta", Toast.LENGTH_SHORT).show()); aVoid -> Toast.makeText(this, "Consulta " + newStatus.toLowerCase(), Toast.LENGTH_SHORT).show())
.addOnFailureListener(
e -> Toast.makeText(this, "Erro ao atualizar consulta", Toast.LENGTH_SHORT).show());
} }
// AGENDA LOGIC // AGENDA LOGIC
private com.google.firebase.firestore.ListenerRegistration agendaListener; private com.google.firebase.firestore.ListenerRegistration agendaListener;
private void loadConsultasAgendaForDate(String dateStr) { private void loadConsultasAgendaForDate(String dateStr) {
if(currentMedicoId == null) return; if (currentMedicoId == null)
return;
if (agendaListener != null) { if (agendaListener != null) {
agendaListener.remove(); agendaListener.remove();
} }
// Using a more robust query approach
agendaListener = db.collection("consultas") agendaListener = db.collection("consultas")
.addSnapshotListener((value, error) -> { .addSnapshotListener((value, error) -> {
if (error != null) { if (error != null) {
Toast.makeText(MainActivity.this, "Erro Firebase: " + error.getMessage(), Toast.LENGTH_SHORT).show(); Toast.makeText(MainActivity.this, "Erro Firebase: " + error.getMessage(), Toast.LENGTH_SHORT)
.show();
return; return;
} }
if (value == null) return; if (value == null)
return;
List<Consulta> consultasList = new ArrayList<>(); List<Consulta> consultasList = new ArrayList<>();
String altDate = getAlternativeDate(dateStr); String altDate = getAlternativeDate(dateStr);
@@ -270,7 +290,6 @@ public class MainActivity extends AppCompatActivity implements ConsultaAdapter.O
if (c != null) { if (c != null) {
c.setId(doc.getId()); c.setId(doc.getId());
// Check if belongs to this doctor (handles both String and Array)
boolean belongsToDoctor = false; boolean belongsToDoctor = false;
Object med = c.getMedicos(); Object med = c.getMedicos();
if (med instanceof String) { if (med instanceof String) {
@@ -306,10 +325,10 @@ public class MainActivity extends AppCompatActivity implements ConsultaAdapter.O
try { try {
String[] parts = ddMMyyyy.split("/"); String[] parts = ddMMyyyy.split("/");
if (parts.length == 3) { if (parts.length == 3) {
// Return YYYY-MM-DD
return parts[2] + "-" + parts[1] + "-" + parts[0]; return parts[2] + "-" + parts[1] + "-" + parts[0];
} }
} catch (Exception e) {} } catch (Exception e) {
}
return ddMMyyyy; return ddMMyyyy;
} }
@@ -329,19 +348,56 @@ public class MainActivity extends AppCompatActivity implements ConsultaAdapter.O
} }
// PERFIL LOGIC // PERFIL LOGIC
private com.google.firebase.firestore.ListenerRegistration perfilListener;
private void loadPerfilMedico() { private void loadPerfilMedico() {
if(currentMedicoId == null) return; if (currentMedicoId == null)
db.collection("medicos").document(currentMedicoId).get().addOnSuccessListener(doc -> { return;
if (doc.exists()) {
String fetchedName = doc.getString("nome"); if (perfilListener != null)
tvNome.setText(fetchedName); perfilListener.remove();
if (tvGreetingMain != null && fetchedName != null) {
tvGreetingMain.setText("Olá, " + fetchedName); // Escuta em tempo real na coleção 'utilizadores'
} perfilListener = db.collection("utilizadores").document(currentMedicoId)
tvEmail.setText(doc.getString("email")); .addSnapshotListener((doc, error) -> {
tvEspecialidade.setText("Especialidade: " + doc.getString("especialidade")); if (doc != null && doc.exists()) {
tvCedula.setText("Cédula: " + doc.getString("cedula_profissional")); updateProfileUI(doc);
} else {
// Fallback para coleção 'medicos'
db.collection("medicos").document(currentMedicoId).get().addOnSuccessListener(docMed -> {
if (docMed.exists())
updateProfileUI(docMed);
});
} }
}); });
} }
private void updateProfileUI(DocumentSnapshot doc) {
String fetchedName = doc.getString("nome_completo");
if (fetchedName == null)
fetchedName = doc.getString("nome");
if (fetchedName != null) {
// Salvar na sessão local para carregamento instantâneo no futuro
getSharedPreferences("SessaoMedico", MODE_PRIVATE)
.edit()
.putString("nome_medico", fetchedName)
.apply();
}
tvNome.setText(fetchedName != null ? fetchedName : "Médico");
if (tvGreetingMain != null) {
String displayName = (fetchedName != null) ? fetchedName
: getSharedPreferences("SessaoMedico", MODE_PRIVATE).getString("nome_medico", "Doutor");
tvGreetingMain.setText("Olá, " + displayName.split(" ")[0]);
}
tvEmail.setText(doc.getString("email"));
tvEspecialidade.setText(
"Especialidade: " + (doc.getString("especialidade") != null ? doc.getString("especialidade") : "--"));
String cedula = doc.getString("cedula_profissional");
if (cedula == null)
cedula = doc.getString("cedula");
tvCedula.setText("Cédula: " + (cedula != null ? cedula : "--"));
}
} }

View File

@@ -74,14 +74,36 @@ public class PerfilMedicoActivity extends AppCompatActivity {
private void carregarPerfil() { private void carregarPerfil() {
if (mAuth.getCurrentUser() != null) { if (mAuth.getCurrentUser() != null) {
String uid = mAuth.getCurrentUser().getUid(); String uid = mAuth.getCurrentUser().getUid();
db.collection("medicos").document(uid).get().addOnSuccessListener(doc -> {
// Tentamos primeiro na coleção 'utilizadores'
db.collection("utilizadores").document(uid).get().addOnSuccessListener(doc -> {
if (doc.exists()) { if (doc.exists()) {
tvNome.setText(doc.getString("nome")); mostrarDados(doc);
tvEmail.setText(doc.getString("email")); } else {
tvEspecialidade.setText("Especialidade: " + doc.getString("especialidade")); // Se não existir em 'utilizadores', tentamos em 'medicos'
tvCedula.setText("Cédula: " + doc.getString("cedula_profissional")); db.collection("medicos").document(uid).get().addOnSuccessListener(docMed -> {
if (docMed.exists()) {
mostrarDados(docMed);
}
});
} }
}).addOnFailureListener(e -> Toast.makeText(this, "Erro ao carregar perfil.", Toast.LENGTH_SHORT).show()); }).addOnFailureListener(e -> Toast.makeText(this, "Erro ao carregar perfil.", Toast.LENGTH_SHORT).show());
} }
} }
private void mostrarDados(com.google.firebase.firestore.DocumentSnapshot doc) {
// Tenta 'nome_completo' (novo) ou 'nome' (antigo)
String nome = doc.getString("nome_completo");
if (nome == null || nome.isEmpty()) nome = doc.getString("nome");
tvNome.setText(nome != null ? nome : "Utilizador sem nome");
tvEmail.setText(doc.getString("email"));
tvEspecialidade.setText("Especialidade: " + (doc.getString("especialidade") != null ? doc.getString("especialidade") : "--"));
// Tenta vários formatos de cédula que possam existir
String cedula = doc.getString("cedula_profissional");
if (cedula == null) cedula = doc.getString("cedula");
tvCedula.setText("Cédula: " + (cedula != null ? cedula : "Não configurada"));
}
} }

View File

@@ -130,23 +130,48 @@ public class RegisterActivity extends AppCompatActivity {
saveMedicoData(user.getUid(), name, specialty, gender, email); saveMedicoData(user.getUid(), name, specialty, gender, email);
} }
} else { } else {
Log.w(TAG, "createUserWithEmail:failure", task.getException()); Exception e = task.getException();
Toast.makeText(RegisterActivity.this, "Falha no registo: " + Log.w(TAG, "createUserWithEmail:failure", e);
(task.getException() != null ? task.getException().getMessage() : "Erro desconhecido"),
Toast.LENGTH_LONG).show(); if (e instanceof com.google.firebase.auth.FirebaseAuthUserCollisionException) {
// Se o utilizador já existe no Auth, tentamos fazer login e gravar os dados
// (caso tenham falhado da última vez)
mAuth.signInWithEmailAndPassword(email, password)
.addOnCompleteListener(loginTask -> {
if (loginTask.isSuccessful()) {
saveMedicoData(mAuth.getCurrentUser().getUid(), name, specialty, gender, email);
} else {
Toast.makeText(RegisterActivity.this, "Este email já está registado. Tente fazer Login.", Toast.LENGTH_LONG).show();
registerButton.setEnabled(true); registerButton.setEnabled(true);
} }
}); });
} else {
Toast.makeText(RegisterActivity.this, "Falha no registo: " +
(e != null ? e.getMessage() : "Erro desconhecido"), Toast.LENGTH_LONG).show();
registerButton.setEnabled(true);
}
}
});
} }
private void saveMedicoData(String uid, String name, String specialty, String gender, String email) { private void saveMedicoData(String uid, String name, String specialty, String gender, String email) {
Medico medico = new Medico(uid, name, email, specialty, gender); java.util.Map<String, Object> medicoMap = new java.util.HashMap<>();
medicoMap.put("id", uid);
medicoMap.put("nome_completo", name);
medicoMap.put("email", email);
medicoMap.put("especialidade", specialty);
medicoMap.put("sexo", gender);
medicoMap.put("tipo", "medico");
db.collection("medicos") // Gravamos em 'utilizadores' como pedido
db.collection("utilizadores")
.document(uid) .document(uid)
.set(medico) .set(medicoMap)
.addOnCompleteListener(task -> { .addOnCompleteListener(task -> {
if (task.isSuccessful()) { if (task.isSuccessful()) {
// Também guardamos em 'medicos' para garantir que as outras partes da app funcionam
db.collection("medicos").document(uid).set(medicoMap);
Log.d(TAG, "saveMedicoData:success"); Log.d(TAG, "saveMedicoData:success");
Toast.makeText(RegisterActivity.this, "Registo efetuado com sucesso!", Toast.LENGTH_SHORT).show(); Toast.makeText(RegisterActivity.this, "Registo efetuado com sucesso!", Toast.LENGTH_SHORT).show();
startActivity(new Intent(RegisterActivity.this, MainActivity.class)); startActivity(new Intent(RegisterActivity.this, MainActivity.class));

View File

@@ -1,11 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android" <shape xmlns:android="http://schemas.android.com/apk/res/android">
android:color="#400066CC"> <stroke android:width="1dp" android:color="?attr/colorPrimary" />
<item> <corners android:radius="28dp" />
<shape android:shape="rectangle">
<solid android:color="@android:color/transparent" /> <solid android:color="@android:color/transparent" />
<stroke android:width="2dp" android:color="@color/primary_color" />
<corners android:radius="8dp" />
</shape> </shape>
</item>
</ripple>

View File

@@ -1,7 +1,7 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules. // Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins { plugins {
id 'com.android.application' version '9.1.1' apply false id 'com.android.application' version '9.2.0' apply false
id 'com.android.library' version '9.1.1' apply false id 'com.android.library' version '9.2.0' apply false
id 'com.google.gms.google-services' version '4.4.4' apply false id 'com.google.gms.google-services' version '4.4.4' apply false
} }

File diff suppressed because one or more lines are too long

View File

@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.1-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.1-bin.zip
networkTimeout=10000 networkTimeout=10000
validateDistributionUrl=true validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME