From 96d19859987600af517e374b882bf5dafb5a2052 Mon Sep 17 00:00:00 2001 From: 230405 <230405@epvc.pt> Date: Tue, 21 Apr 2026 17:09:44 +0100 Subject: [PATCH] nao esta a funcionar o recycler view --- .gradle/9.3.1/fileHashes/fileHashes.bin | Bin 228769 -> 228769 bytes .gradle/9.3.1/fileHashes/fileHashes.lock | Bin 17 -> 17 bytes .../buildOutputCleanup.lock | Bin 17 -> 17 bytes .gradle/buildOutputCleanup/cache.properties | 4 +- .gradle/buildOutputCleanup/outputFiles.bin | Bin 54833 -> 0 bytes .idea/misc.xml | 3 +- .../medcuida/pro/DetalhePacienteActivity.java | 28 +- .../medcuida/pro/EditarPerfilActivity.java | 16 +- .../example/medcuida/pro/MainActivity.java | 344 ++++++++++-------- .../medcuida/pro/PerfilMedicoActivity.java | 32 +- .../pro/ui/auth/RegisterActivity.java | 41 ++- .../main/res/drawable/btn_outline_primary.xml | 15 +- build.gradle | 4 +- build/reports/problems/problems-report.html | 11 +- gradle/wrapper/gradle-wrapper.properties | 2 +- 15 files changed, 317 insertions(+), 183 deletions(-) delete mode 100644 .gradle/buildOutputCleanup/outputFiles.bin diff --git a/.gradle/9.3.1/fileHashes/fileHashes.bin b/.gradle/9.3.1/fileHashes/fileHashes.bin index c9753d4df5c5795763c5d193189d1c76d55cbffc..3953a133538333aaacfcaa7db50b27d9e74979c9 100644 GIT binary patch delta 26 icmZ4Zn|I-F-i8*&7N#xCs%0!2GM993*DPbMU1jhgX literal 17 VcmZRMl)ssC;8#Ti0~iQr001=;1jYaW diff --git a/.gradle/buildOutputCleanup/cache.properties b/.gradle/buildOutputCleanup/cache.properties index c67d65d..8d21bd0 100644 --- a/.gradle/buildOutputCleanup/cache.properties +++ b/.gradle/buildOutputCleanup/cache.properties @@ -1,2 +1,2 @@ -#Thu Mar 12 10:18:44 WET 2026 -gradle.version=9.3.1 +#Tue Apr 21 15:25:11 WEST 2026 +gradle.version=9.4.1 diff --git a/.gradle/buildOutputCleanup/outputFiles.bin b/.gradle/buildOutputCleanup/outputFiles.bin deleted file mode 100644 index 8e1d0d64c59857070da619def69813f164ab984e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 54833 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 - + diff --git a/app/src/main/java/com/example/medcuida/pro/DetalhePacienteActivity.java b/app/src/main/java/com/example/medcuida/pro/DetalhePacienteActivity.java index aa59616..1ad9583 100644 --- a/app/src/main/java/com/example/medcuida/pro/DetalhePacienteActivity.java +++ b/app/src/main/java/com/example/medcuida/pro/DetalhePacienteActivity.java @@ -109,9 +109,33 @@ public class DetalhePacienteActivity extends AppCompatActivity { tvNumeroUtente.setText("Nº Utente: " + (numUtente != null ? numUtente : "N/D")); tvSexo.setText("Sexo: " + (sexo != null ? sexo : "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 { Log.d(TAG, "No such document"); Toast.makeText(DetalhePacienteActivity.this, "Paciente não encontrado", Toast.LENGTH_SHORT).show(); diff --git a/app/src/main/java/com/example/medcuida/pro/EditarPerfilActivity.java b/app/src/main/java/com/example/medcuida/pro/EditarPerfilActivity.java index 0642399..0708cef 100644 --- a/app/src/main/java/com/example/medcuida/pro/EditarPerfilActivity.java +++ b/app/src/main/java/com/example/medcuida/pro/EditarPerfilActivity.java @@ -69,13 +69,13 @@ public class EditarPerfilActivity extends AppCompatActivity { } private void carregarDados() { - db.collection("medicos").document(currentUserId).get().addOnSuccessListener(doc -> { + db.collection("utilizadores").document(currentUserId).get().addOnSuccessListener(doc -> { if (doc.exists()) { - nameEditText.setText(doc.getString("nome")); + nameEditText.setText(doc.getString("nome_completo")); specialtyEditText.setText(doc.getString("especialidade")); emailEditText.setText(doc.getString("email")); - String gender = doc.getString("gender"); + String gender = doc.getString("sexo"); if (gender != null) { genderAutoComplete.setText(gender, false); } @@ -101,13 +101,17 @@ public class EditarPerfilActivity extends AppCompatActivity { btnGuardar.setEnabled(false); Map updates = new HashMap<>(); - updates.put("nome", name); + updates.put("nome_completo", name); 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) .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(); setResult(RESULT_OK); finish(); diff --git a/app/src/main/java/com/example/medcuida/pro/MainActivity.java b/app/src/main/java/com/example/medcuida/pro/MainActivity.java index 4d1a43d..b55a4b9 100644 --- a/app/src/main/java/com/example/medcuida/pro/MainActivity.java +++ b/app/src/main/java/com/example/medcuida/pro/MainActivity.java @@ -30,7 +30,8 @@ import java.util.Date; import java.util.List; 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; @@ -47,7 +48,7 @@ public class MainActivity extends AppCompatActivity implements ConsultaAdapter.O // Perfil private TextView tvNome, tvEmail, tvEspecialidade, tvCedula; private MaterialButton btnLogout, btnEditarDados; - + // Header private TextView tvGreetingMain; @@ -58,7 +59,7 @@ public class MainActivity extends AppCompatActivity implements ConsultaAdapter.O @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - + try { setContentView(R.layout.activity_main); } catch (Exception e) { @@ -79,85 +80,91 @@ public class MainActivity extends AppCompatActivity implements ConsultaAdapter.O currentMedicoId = mAuth.getCurrentUser().getUid(); - // Bind Views - viewAgenda = findViewById(R.id.view_agenda); - viewPacientes = findViewById(R.id.view_pacientes); - viewPerfil = findViewById(R.id.view_perfil); - layTop = findViewById(R.id.lay_top); - - tvGreetingMain = findViewById(R.id.tv_greeting_main); + // Bind Views + viewAgenda = findViewById(R.id.view_agenda); + viewPacientes = findViewById(R.id.view_pacientes); + viewPerfil = findViewById(R.id.view_perfil); + layTop = findViewById(R.id.lay_top); - // Bind Pacientes - recyclerConsultas = findViewById(R.id.recycler_consultas); - textEmptyState = findViewById(R.id.text_empty_state); - recyclerConsultas.setLayoutManager(new LinearLayoutManager(this)); - adapterPacientes = new PacienteAdapter(paciente -> { - // Ação ao clicar no paciente (ex: abrir chat ou detalhes) - Intent intent = new Intent(MainActivity.this, DetalhePacienteActivity.class); - intent.putExtra("PACIENTE_ID", paciente.getId()); - startActivity(intent); - }); - recyclerConsultas.setAdapter(adapterPacientes); + tvGreetingMain = findViewById(R.id.tv_greeting_main); - // Bind Agenda - recyclerAgenda = findViewById(R.id.recycler_agenda); - textAgendaVazia = findViewById(R.id.text_agenda_vazia); - CalendarView calendarView = findViewById(R.id.calendarView); - recyclerAgenda.setLayoutManager(new LinearLayoutManager(this)); - adapterAgenda = new ConsultaAdapter(this, consulta -> { - Intent intent = new Intent(MainActivity.this, DetalhePacienteActivity.class); - intent.putExtra("PACIENTE_ID", consulta.getPacienteId()); - intent.putExtra("CONSULTA_ID", consulta.getId()); - startActivity(intent); - }); - recyclerAgenda.setAdapter(adapterAgenda); - - // Bind Perfil - tvNome = findViewById(R.id.tv_nome_medico); - tvEmail = findViewById(R.id.tv_email_medico); - tvEspecialidade = findViewById(R.id.tv_especialidade); - tvCedula = findViewById(R.id.tv_cedula); - btnLogout = findViewById(R.id.btn_logout); - btnEditarDados = findViewById(R.id.btn_editar_dados); - - btnEditarDados.setOnClickListener(v -> { - startActivity(new Intent(MainActivity.this, EditarPerfilActivity.class)); - }); - - btnLogout.setOnClickListener(v -> { - mAuth.signOut(); - Intent intent = new Intent(this, LoginActivity.class); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); - startActivity(intent); - }); - - // Setup BottomNavigation - BottomNavigationView bottomNav = findViewById(R.id.bottom_navigation); - bottomNav.setSelectedItemId(R.id.nav_agenda); - bottomNav.setOnItemSelectedListener(item -> { - viewAgenda.setVisibility(View.GONE); - viewPacientes.setVisibility(View.GONE); - viewPerfil.setVisibility(View.GONE); - layTop.setVisibility(View.GONE); - - if (item.getItemId() == R.id.nav_agenda) { - viewAgenda.setVisibility(View.VISIBLE); - layTop.setVisibility(View.VISIBLE); - return true; - } else if (item.getItemId() == R.id.nav_pacientes) { - viewPacientes.setVisibility(View.VISIBLE); - return true; - } else if (item.getItemId() == R.id.nav_perfil) { - viewPerfil.setVisibility(View.VISIBLE); - return true; + // 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]); } - return false; - }); + + // Bind Pacientes + recyclerConsultas = findViewById(R.id.recycler_consultas); + textEmptyState = findViewById(R.id.text_empty_state); + recyclerConsultas.setLayoutManager(new LinearLayoutManager(this)); + adapterPacientes = new PacienteAdapter(paciente -> { + // Ação ao clicar no paciente (ex: abrir chat ou detalhes) + Intent intent = new Intent(MainActivity.this, DetalhePacienteActivity.class); + intent.putExtra("PACIENTE_ID", paciente.getId()); + startActivity(intent); + }); + recyclerConsultas.setAdapter(adapterPacientes); + + // Bind Agenda + recyclerAgenda = findViewById(R.id.recycler_agenda); + textAgendaVazia = findViewById(R.id.text_agenda_vazia); + CalendarView calendarView = findViewById(R.id.calendarView); + recyclerAgenda.setLayoutManager(new LinearLayoutManager(this)); + adapterAgenda = new ConsultaAdapter(this, consulta -> { + Intent intent = new Intent(MainActivity.this, DetalhePacienteActivity.class); + intent.putExtra("PACIENTE_ID", consulta.getPacienteId()); + intent.putExtra("CONSULTA_ID", consulta.getId()); + startActivity(intent); + }); + recyclerAgenda.setAdapter(adapterAgenda); + + // Bind Perfil + tvNome = findViewById(R.id.tv_nome_medico); + tvEmail = findViewById(R.id.tv_email_medico); + tvEspecialidade = findViewById(R.id.tv_especialidade); + tvCedula = findViewById(R.id.tv_cedula); + btnLogout = findViewById(R.id.btn_logout); + btnEditarDados = findViewById(R.id.btn_editar_dados); + + btnEditarDados.setOnClickListener(v -> { + startActivity(new Intent(MainActivity.this, EditarPerfilActivity.class)); + }); + + btnLogout.setOnClickListener(v -> { + mAuth.signOut(); + Intent intent = new Intent(this, LoginActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); + startActivity(intent); + }); + + // Setup BottomNavigation + BottomNavigationView bottomNav = findViewById(R.id.bottom_navigation); + bottomNav.setSelectedItemId(R.id.nav_agenda); + bottomNav.setOnItemSelectedListener(item -> { + viewAgenda.setVisibility(View.GONE); + viewPacientes.setVisibility(View.GONE); + viewPerfil.setVisibility(View.GONE); + layTop.setVisibility(View.GONE); + + if (item.getItemId() == R.id.nav_agenda) { + viewAgenda.setVisibility(View.VISIBLE); + layTop.setVisibility(View.VISIBLE); + return true; + } else if (item.getItemId() == R.id.nav_pacientes) { + viewPacientes.setVisibility(View.VISIBLE); + return true; + } else if (item.getItemId() == R.id.nav_perfil) { + viewPerfil.setVisibility(View.VISIBLE); + return true; + } + return false; + }); // Load Initial Data loadUtilizadores(); loadPerfilMedico(); - + SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy", Locale.getDefault()); String today = sdf.format(new Date()); TextView textAgendaInfoInit = findViewById(R.id.text_agenda_info); @@ -174,8 +181,8 @@ public class MainActivity extends AppCompatActivity implements ConsultaAdapter.O } loadConsultasAgendaForDate(selectedDate); }); - - } catch(Exception e) { + + } catch (Exception e) { Toast.makeText(this, "Erro Init: " + e.getMessage(), Toast.LENGTH_LONG).show(); } } @@ -185,7 +192,7 @@ public class MainActivity extends AppCompatActivity implements ConsultaAdapter.O db.collection("utilizadores") .addSnapshotListener((value, error) -> { 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; } List pacientesList = new ArrayList<>(); @@ -194,14 +201,23 @@ public class MainActivity extends AppCompatActivity implements ConsultaAdapter.O Paciente p = doc.toObject(Paciente.class); if (p != null) { p.setId(doc.getId()); - // Garantir que o nome está preenchido - if (p.getNome() == null) p.setNome(doc.getString("nome")); - if (p.getEmail() == null) p.setEmail(doc.getString("email")); - pacientesList.add(p); + // Tenta 'nome_completo' primeiro, depois 'nome' + String nomeVal = doc.getString("nome_completo"); + 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); + } } } } - + if (pacientesList.isEmpty()) { textEmptyState.setVisibility(View.VISIBLE); recyclerConsultas.setVisibility(View.GONE); @@ -225,7 +241,7 @@ public class MainActivity extends AppCompatActivity implements ConsultaAdapter.O .addOnSuccessListener(aVoid -> Toast.makeText(this, "Consulta eliminada", Toast.LENGTH_SHORT).show()) .addOnFailureListener(e -> Toast.makeText(this, "Erro ao eliminar", Toast.LENGTH_SHORT).show()); } - + @Override public void onConsultaClick(Consulta consulta) { Intent intent = new Intent(this, DetalhePacienteActivity.class); @@ -237,79 +253,82 @@ public class MainActivity extends AppCompatActivity implements ConsultaAdapter.O private void updateConsultaStatus(String consultaId, String newStatus) { db.collection("consultas").document(consultaId) .update("status", newStatus) - .addOnSuccessListener(aVoid -> Toast.makeText(this, "Consulta " + newStatus.toLowerCase(), Toast.LENGTH_SHORT).show()) - .addOnFailureListener(e -> Toast.makeText(this, "Erro ao atualizar consulta", Toast.LENGTH_SHORT).show()); + .addOnSuccessListener( + 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 private com.google.firebase.firestore.ListenerRegistration agendaListener; private void loadConsultasAgendaForDate(String dateStr) { - if(currentMedicoId == null) return; - + if (currentMedicoId == null) + return; + if (agendaListener != null) { agendaListener.remove(); } - // Using a more robust query approach agendaListener = db.collection("consultas") - .addSnapshotListener((value, error) -> { - if (error != null) { - Toast.makeText(MainActivity.this, "Erro Firebase: " + error.getMessage(), Toast.LENGTH_SHORT).show(); - return; - } - - if (value == null) return; + .addSnapshotListener((value, error) -> { + if (error != null) { + Toast.makeText(MainActivity.this, "Erro Firebase: " + error.getMessage(), Toast.LENGTH_SHORT) + .show(); + return; + } - List consultasList = new ArrayList<>(); - String altDate = getAlternativeDate(dateStr); - String isoDate = convertToISODate(dateStr); + if (value == null) + return; - for (QueryDocumentSnapshot doc : value) { - Consulta c = doc.toObject(Consulta.class); - if (c != null) { - c.setId(doc.getId()); - - // Check if belongs to this doctor (handles both String and Array) - boolean belongsToDoctor = false; - Object med = c.getMedicos(); - if (med instanceof String) { - belongsToDoctor = ((String) med).equals(currentMedicoId); - } else if (med instanceof List) { - belongsToDoctor = ((List) med).contains(currentMedicoId); - } + List consultasList = new ArrayList<>(); + String altDate = getAlternativeDate(dateStr); + String isoDate = convertToISODate(dateStr); - if (belongsToDoctor) { - String cData = c.getData() != null ? c.getData().trim() : ""; - if (cData.equals(dateStr) || cData.equals(altDate) || cData.equals(isoDate)) { - if (c.getStatus() == null || !"cancelada".equalsIgnoreCase(c.getStatus())) { - consultasList.add(c); + for (QueryDocumentSnapshot doc : value) { + Consulta c = doc.toObject(Consulta.class); + if (c != null) { + c.setId(doc.getId()); + + boolean belongsToDoctor = false; + Object med = c.getMedicos(); + if (med instanceof String) { + belongsToDoctor = ((String) med).equals(currentMedicoId); + } else if (med instanceof List) { + belongsToDoctor = ((List) med).contains(currentMedicoId); + } + + if (belongsToDoctor) { + String cData = c.getData() != null ? c.getData().trim() : ""; + if (cData.equals(dateStr) || cData.equals(altDate) || cData.equals(isoDate)) { + if (c.getStatus() == null || !"cancelada".equalsIgnoreCase(c.getStatus())) { + consultasList.add(c); + } } } } } - } - - adapterAgenda.setConsultas(consultasList); - - if (consultasList.isEmpty()) { - textAgendaVazia.setVisibility(View.VISIBLE); - recyclerAgenda.setVisibility(View.GONE); - } else { - textAgendaVazia.setVisibility(View.GONE); - recyclerAgenda.setVisibility(View.VISIBLE); - } - }); + + adapterAgenda.setConsultas(consultasList); + + if (consultasList.isEmpty()) { + textAgendaVazia.setVisibility(View.VISIBLE); + recyclerAgenda.setVisibility(View.GONE); + } else { + textAgendaVazia.setVisibility(View.GONE); + recyclerAgenda.setVisibility(View.VISIBLE); + } + }); } private String convertToISODate(String ddMMyyyy) { try { String[] parts = ddMMyyyy.split("/"); if (parts.length == 3) { - // Return YYYY-MM-DD return parts[2] + "-" + parts[1] + "-" + parts[0]; } - } catch (Exception e) {} + } catch (Exception e) { + } return ddMMyyyy; } @@ -329,19 +348,56 @@ public class MainActivity extends AppCompatActivity implements ConsultaAdapter.O } // PERFIL LOGIC + private com.google.firebase.firestore.ListenerRegistration perfilListener; + private void loadPerfilMedico() { - if(currentMedicoId == null) return; - db.collection("medicos").document(currentMedicoId).get().addOnSuccessListener(doc -> { - if (doc.exists()) { - String fetchedName = doc.getString("nome"); - tvNome.setText(fetchedName); - if (tvGreetingMain != null && fetchedName != null) { - tvGreetingMain.setText("Olá, " + fetchedName); - } - tvEmail.setText(doc.getString("email")); - tvEspecialidade.setText("Especialidade: " + doc.getString("especialidade")); - tvCedula.setText("Cédula: " + doc.getString("cedula_profissional")); - } - }); + if (currentMedicoId == null) + return; + + if (perfilListener != null) + perfilListener.remove(); + + // Escuta em tempo real na coleção 'utilizadores' + perfilListener = db.collection("utilizadores").document(currentMedicoId) + .addSnapshotListener((doc, error) -> { + if (doc != null && doc.exists()) { + 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 : "--")); } } diff --git a/app/src/main/java/com/example/medcuida/pro/PerfilMedicoActivity.java b/app/src/main/java/com/example/medcuida/pro/PerfilMedicoActivity.java index 840f403..604e0e1 100644 --- a/app/src/main/java/com/example/medcuida/pro/PerfilMedicoActivity.java +++ b/app/src/main/java/com/example/medcuida/pro/PerfilMedicoActivity.java @@ -74,14 +74,36 @@ public class PerfilMedicoActivity extends AppCompatActivity { private void carregarPerfil() { if (mAuth.getCurrentUser() != null) { 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()) { - tvNome.setText(doc.getString("nome")); - tvEmail.setText(doc.getString("email")); - tvEspecialidade.setText("Especialidade: " + doc.getString("especialidade")); - tvCedula.setText("Cédula: " + doc.getString("cedula_profissional")); + mostrarDados(doc); + } else { + // Se não existir em 'utilizadores', tentamos em 'medicos' + 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()); } } + + 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")); + } } diff --git a/app/src/main/java/com/example/medcuida/pro/ui/auth/RegisterActivity.java b/app/src/main/java/com/example/medcuida/pro/ui/auth/RegisterActivity.java index 547dd2d..63e26c2 100644 --- a/app/src/main/java/com/example/medcuida/pro/ui/auth/RegisterActivity.java +++ b/app/src/main/java/com/example/medcuida/pro/ui/auth/RegisterActivity.java @@ -130,23 +130,48 @@ public class RegisterActivity extends AppCompatActivity { saveMedicoData(user.getUid(), name, specialty, gender, email); } } else { - Log.w(TAG, "createUserWithEmail:failure", task.getException()); - Toast.makeText(RegisterActivity.this, "Falha no registo: " + - (task.getException() != null ? task.getException().getMessage() : "Erro desconhecido"), - Toast.LENGTH_LONG).show(); - registerButton.setEnabled(true); + Exception e = task.getException(); + Log.w(TAG, "createUserWithEmail:failure", e); + + 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); + } + }); + } 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) { - Medico medico = new Medico(uid, name, email, specialty, gender); + java.util.Map 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) - .set(medico) + .set(medicoMap) .addOnCompleteListener(task -> { 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"); Toast.makeText(RegisterActivity.this, "Registo efetuado com sucesso!", Toast.LENGTH_SHORT).show(); startActivity(new Intent(RegisterActivity.this, MainActivity.class)); diff --git a/app/src/main/res/drawable/btn_outline_primary.xml b/app/src/main/res/drawable/btn_outline_primary.xml index 2814431..a631efd 100644 --- a/app/src/main/res/drawable/btn_outline_primary.xml +++ b/app/src/main/res/drawable/btn_outline_primary.xml @@ -1,11 +1,6 @@ - - - - - - - - - + + + + + diff --git a/build.gradle b/build.gradle index dc81a29..2ea6f5d 100644 --- a/build.gradle +++ b/build.gradle @@ -1,7 +1,7 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. plugins { - id 'com.android.application' version '9.1.1' apply false - id 'com.android.library' version '9.1.1' apply false + id 'com.android.application' version '9.2.0' apply false + id 'com.android.library' version '9.2.0' apply false id 'com.google.gms.google-services' version '4.4.4' apply false } diff --git a/build/reports/problems/problems-report.html b/build/reports/problems/problems-report.html index 9b9cf70..b975f2e 100644 --- a/build/reports/problems/problems-report.html +++ b/build/reports/problems/problems-report.html @@ -629,6 +629,13 @@ code + .copy-button { color: #686868; } +.problem-detail { + color: #02303A; + font-size: 14px; + margin: 0; + padding: 0; +} + @@ -646,12 +653,12 @@ code + .copy-button { diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 37f78a6..c61a118 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME 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 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME