falta so o chat

This commit is contained in:
2026-04-22 12:41:12 +01:00
parent 96d1985998
commit 2f3b03fe05
444 changed files with 22203 additions and 20079 deletions

108
docs/00_VISAO_GERAL.md Normal file
View File

@@ -0,0 +1,108 @@
# 📋 Med Cuida+ — Visão Geral do Projeto
## O que é?
O **Med Cuida+** é uma aplicação Android destinada a **médicos**, permitindo-lhes gerir os seus pacientes, consultas e perfil profissional. A aplicação comunica com o **Firebase** (Authentication + Firestore) para guardar e sincronizar dados em tempo real.
---
## 🏗️ Estrutura do Projeto
```
com.example.medcuida.pro/
├── MainActivity.java ← Ecrã principal (Agenda + Pacientes + Perfil)
├── AgendaActivity.java ← Ecrã de agenda alternativo (com calendário)
├── ChatActivity.java ← Chat em tempo real entre médico e paciente
├── DetalhePacienteActivity.java ← Detalhes de um paciente específico
├── EditarPerfilActivity.java ← Edição do perfil do médico
├── PerfilMedicoActivity.java ← Visualização do perfil do médico
├── models/ ← Classes de dados (POJOs)
│ ├── Consulta.java ← Modelo de uma consulta médica
│ ├── Medico.java ← Modelo de um médico
│ ├── Mensagem.java ← Modelo de uma mensagem de chat
│ └── Paciente.java ← Modelo de um paciente
├── ui/
│ ├── adapters/ ← Adaptadores para listas (RecyclerView)
│ │ ├── ConsultaAdapter.java ← Lista de consultas na agenda
│ │ ├── MensagemAdapter.java ← Lista de mensagens no chat
│ │ └── PacienteAdapter.java ← Lista de pacientes
│ │
│ └── auth/ ← Autenticação
│ ├── LoginActivity.java ← Ecrã de login
│ └── RegisterActivity.java ← Ecrã de registo de médico
└── services/ ← (Vazio — reservado para serviços futuros)
```
---
## 🔧 Tecnologias Utilizadas
| Tecnologia | Versão | Finalidade |
|---|---|---|
| **Android SDK** | compileSdk 35 / minSdk 24 | Plataforma base |
| **Java** | 1.8 | Linguagem de programação |
| **Firebase Auth** | via BoM 32.7.2 | Autenticação de utilizadores |
| **Firebase Firestore** | via BoM 32.7.2 | Base de dados em tempo real |
| **Material Design** | 1.11.0 | Componentes visuais modernos |
| **Navigation Component** | 2.7.7 | Navegação entre fragments |
| **Retrofit + OkHttp** | 2.9.0 / 4.10.0 | Chamadas HTTP e JSON |
| **Google Generative AI** | Última versão | Integração com Gemini AI |
| **Guava** | 31.1 | Operações assíncronas |
---
## 🗄️ Coleções Firestore
| Coleção | Descrição |
|---|---|
| `utilizadores` | Todos os utilizadores (pacientes e médicos) |
| `medicos` | Dados específicos dos médicos (duplicado para compatibilidade) |
| `consultas` | Consultas médicas agendadas |
| `consultas/{id}/mensagens` | Sub-coleção com mensagens de chat de uma consulta |
| `medicamentos` | Medicamentos registados por pacientes |
---
## 🔄 Fluxo da Aplicação
```mermaid
graph TD
A[LoginActivity] -->|Credenciais válidas| B{Verificar Perfil}
B -->|Existe em 'medicos'| C[MainActivity]
B -->|Existe em 'utilizadores'| C
B -->|Não existe| D[Erro: Sem perfil]
E[RegisterActivity] -->|Registo com sucesso| C
C -->|Tab Agenda| F[Ver Consultas do Dia]
C -->|Tab Pacientes| G[Lista de Pacientes]
C -->|Tab Perfil| H[Ver/Editar Perfil]
F -->|Clicar consulta| I[DetalhePacienteActivity]
G -->|Clicar paciente| I
I -->|Botão Chat| J[ChatActivity]
H -->|Editar| K[EditarPerfilActivity]
```
---
## 📁 Índice da Documentação
| Ficheiro | Conteúdo |
|---|---|
| [01_MainActivity.md](./01_MainActivity.md) | Ecrã principal com 3 tabs |
| [02_AgendaActivity.md](./02_AgendaActivity.md) | Agenda alternativa com calendário |
| [03_ChatActivity.md](./03_ChatActivity.md) | Chat em tempo real |
| [04_DetalhePacienteActivity.md](./04_DetalhePacienteActivity.md) | Detalhes do paciente |
| [05_EditarPerfilActivity.md](./05_EditarPerfilActivity.md) | Edição do perfil médico |
| [06_PerfilMedicoActivity.md](./06_PerfilMedicoActivity.md) | Visualização do perfil |
| [07_Models.md](./07_Models.md) | Classes de dados (Consulta, Medico, etc.) |
| [08_Adapters.md](./08_Adapters.md) | Adaptadores RecyclerView |
| [09_Autenticacao.md](./09_Autenticacao.md) | Login e Registo |
| [10_Configuracao_Gradle.md](./10_Configuracao_Gradle.md) | Configuração do projeto |
| [11_Layouts_XML.md](./11_Layouts_XML.md) | Layouts das Activities e itens RecyclerView |
| [12_Layouts_Extras_e_Drawables.md](./12_Layouts_Extras_e_Drawables.md) | Fragments, Dialogs e recursos visuais |

165
docs/01_MainActivity.md Normal file
View File

@@ -0,0 +1,165 @@
# 🏠 MainActivity.java — Ecrã Principal
> **Ficheiro:** `app/src/main/java/com/example/medcuida/pro/MainActivity.java`
> **Layout:** `activity_main.xml`
> **Linhas de código:** 404
---
## Descrição Geral
A `MainActivity` é o **ecrã central da aplicação**. Funciona como um painel de controlo do médico, com **3 secções** controladas por uma `BottomNavigationView`:
| Tab | Conteúdo |
|---|---|
| 📅 **Agenda** | Calendário + lista de consultas do dia selecionado |
| 👥 **Pacientes** | Lista de todos os pacientes registados |
| 👤 **Perfil** | Dados do médico (nome, email, especialidade, cédula) |
---
## Inicialização (`onCreate`) — Linhas 59188
### 1. Configuração do Layout (Linhas 6369)
```java
setContentView(R.layout.activity_main);
```
- Carrega o layout XML
- Envolto em `try-catch` para capturar erros de inflação da view
### 2. Verificação de Autenticação (Linhas 7179)
```java
if (mAuth.getCurrentUser() == null) {
startActivity(new Intent(this, LoginActivity.class));
finish();
return;
}
```
- Se o utilizador **não está autenticado**, redireciona para o `LoginActivity`
- Obtém o `uid` do médico atual para filtrar dados
### 3. Carregamento do Nome em Cache (Linhas 9195)
```java
String cachedName = getSharedPreferences("SessaoMedico", MODE_PRIVATE).getString("nome_medico", "");
```
- Lê o nome do médico das `SharedPreferences` para **exibição instantânea** (sem esperar pelo Firestore)
- Mostra "Olá, [Primeiro Nome]" no topo
### 4. Configuração dos Pacientes (Linhas 97107)
- Cria um `RecyclerView` com `PacienteAdapter`
- Ao clicar num paciente → abre `DetalhePacienteActivity`
### 5. Configuração da Agenda (Linhas 109120)
- Cria um `RecyclerView` com `ConsultaAdapter`
- Ao clicar numa consulta → abre `DetalhePacienteActivity` com ID da consulta
### 6. Configuração do Perfil (Linhas 122139)
- Associa os `TextView` do perfil (nome, email, especialidade, cédula)
- **Botão "Editar Dados"** → abre `EditarPerfilActivity`
- **Botão "Logout"** → faz sign out e redireciona para login
### 7. Bottom Navigation (Linhas 141162)
```java
bottomNav.setOnItemSelectedListener(item -> {
// Esconde todas as views
// Mostra apenas a view selecionada
});
```
- Controla a visibilidade das 3 secções (Agenda, Pacientes, Perfil)
- A tab **Agenda** é a selecionada por defeito
### 8. Carregamento de Dados (Linhas 164183)
- Chama `loadUtilizadores()` para carregar pacientes
- Chama `loadPerfilMedico()` para carregar o perfil
- Configura o `CalendarView` para filtrar consultas por data
---
## Lógica dos Pacientes — Linhas 190230
### `loadUtilizadores()`
```java
db.collection("utilizadores").addSnapshotListener(...)
```
**O que faz:**
1. Escuta **em tempo real** a coleção `utilizadores` no Firestore
2. Para cada documento:
- Converte para objeto `Paciente`
- Tenta o campo `nome_completo`, depois `nome` como fallback
- Filtra: apenas inclui se `tipo` for `"paciente"` ou não estiver definido
3. Atualiza o `RecyclerView` ou mostra mensagem "vazio"
---
## Ações nas Consultas — Linhas 232260
### `onAceitarClick(Consulta)` — Linha 233
- Atualiza o campo `status` da consulta para `"aceite"` no Firestore
### `onEliminarClick(Consulta)` — Linha 238
- **Elimina** o documento da consulta do Firestore
### `onConsultaClick(Consulta)` — Linha 246
- Abre o `DetalhePacienteActivity` com os IDs do paciente e da consulta
### `updateConsultaStatus()` — Linha 253
- Método auxiliar que atualiza o campo `status` de uma consulta
---
## Lógica da Agenda — Linhas 262342
### `loadConsultasAgendaForDate(String dateStr)`
**O que faz:**
1. Remove qualquer listener anterior (para evitar duplicados)
2. Escuta **todas** as consultas em tempo real
3. Para cada consulta:
- Verifica se **pertence ao médico atual** (campo `medicos` pode ser `String` ou `List`)
- Verifica se a **data corresponde** à data selecionada (suporta 3 formatos: `dd/MM/yyyy`, `d/M/yyyy`, `yyyy-MM-dd`)
- Exclui consultas com status `"cancelada"`
4. Atualiza a lista na UI
### `convertToISODate()` — Linha 324
- Converte `"22/04/2026"``"2026-04-22"`
### `getAlternativeDate()` — Linha 335
- Converte `"01/04/2026"``"1/4/2026"` (sem zeros à esquerda)
---
## Lógica do Perfil — Linhas 350402
### `loadPerfilMedico()`
1. Escuta em tempo real na coleção `utilizadores`
2. Se o documento **não existe**, faz fallback para a coleção `medicos`
3. Chama `updateProfileUI()` com os dados encontrados
### `updateProfileUI(DocumentSnapshot doc)`
1.`nome_completo` (ou `nome` como fallback)
2. Guarda o nome nas `SharedPreferences` para cache
3. Atualiza todos os campos da UI:
- Nome, Email, Especialidade, Cédula profissional
- Saudação "Olá, [Nome]" no topo
---
## Diagrama de Fluxo
```mermaid
graph TD
A[onCreate] --> B{Utilizador autenticado?}
B -->|Não| C[Ir para Login]
B -->|Sim| D[Carregar UI]
D --> E[Carregar nome em cache]
D --> F[Configurar RecyclerViews]
D --> G[Configurar BottomNav]
D --> H[loadUtilizadores]
D --> I[loadPerfilMedico]
D --> J[loadConsultasAgendaForDate - hoje]
G -->|Tab Agenda| K[Mostrar Agenda]
G -->|Tab Pacientes| L[Mostrar Pacientes]
G -->|Tab Perfil| M[Mostrar Perfil]
```

136
docs/02_AgendaActivity.md Normal file
View File

@@ -0,0 +1,136 @@
# 📅 AgendaActivity.java — Ecrã de Agenda
> **Ficheiro:** `app/src/main/java/com/example/medcuida/pro/AgendaActivity.java`
> **Layout:** `activity_agenda.xml`
> **Linhas de código:** 192
---
## Descrição Geral
A `AgendaActivity` é um **ecrã dedicado à gestão da agenda do médico**. Mostra um calendário interativo e, abaixo dele, a lista de consultas para o dia selecionado.
> ⚠️ Esta Activity funciona de forma **semelhante à tab Agenda do MainActivity**, mas é uma Activity separada, acessível a partir de outras partes da app.
---
## Inicialização (`onCreate`) — Linhas 3693
### 1. Configuração dos Componentes (Linhas 4348)
```java
CalendarView calendarView = findViewById(R.id.calendarView);
recyclerAgenda = findViewById(R.id.recycler_agenda);
textAgendaVazia = findViewById(R.id.text_agenda_vazia);
```
- `CalendarView` → Calendário nativo do Android
- `RecyclerView` → Lista das consultas
- `TextView` → Mensagem quando não há consultas
### 2. Bottom Navigation (Linhas 4962)
```java
bottomNav.setSelectedItemId(R.id.nav_agenda);
```
- Marca a tab "Agenda" como ativa
- Navegação para `MainActivity` (Pacientes) e `PerfilMedicoActivity` (Perfil)
### 3. Configuração do Adapter (Linhas 6480)
```java
adapter = new ConsultaAdapter(
new ConsultaAdapter.OnConsultaActionClickListener() {
void onAceitarClick(Consulta consulta) { aceitarConsulta(consulta); }
void onEliminarClick(Consulta consulta) { eliminarConsulta(consulta); }
},
consulta -> { /* abrir detalhes */ }
);
```
- Implementa dois callbacks:
- **Aceitar** → muda o status para `"aceite"`
- **Eliminar** → remove a consulta do Firestore
- Clique no item → abre `DetalhePacienteActivity`
### 4. Carregamento Inicial (Linhas 8293)
```java
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy", Locale.getDefault());
loadConsultasForDate(sdf.format(new Date()));
```
- Obtém o UID do médico autenticado
- Carrega as consultas de **hoje**
- Configura o listener do calendário para mudar de dia
---
## Carregamento de Consultas — Linhas 96153
### `loadConsultasForDate(String dateStr)`
**Passo a passo:**
1. **Remove o listener anterior** para evitar fugas de memória
2. **Escuta em tempo real** toda a coleção `consultas`
3. Para cada documento:
- Converte para `Consulta`
- **Verifica se pertence ao médico:**
```java
Object med = c.getMedicos();
if (med instanceof String) { ... }
else if (med instanceof List) { ... }
```
- **Filtra por data** (suporta 3 formatos diferentes)
- **Exclui consultas canceladas**
4. Atualiza o adapter e mostra/esconde a mensagem "vazia"
---
## Ações nas Consultas — Linhas 155171
### `aceitarConsulta(Consulta)`
```java
db.collection("consultas").document(consulta.getId())
.update("status", "aceite")
```
- Atualiza o status para `"aceite"` no Firestore
- Mostra toast de sucesso ou erro
### `eliminarConsulta(Consulta)`
```java
db.collection("consultas").document(consulta.getId())
.delete()
```
- **Apaga permanentemente** a consulta do Firestore
- Mostra toast de sucesso ou erro
---
## Métodos Auxiliares de Data — Linhas 173190
### `convertToISODate(String ddMMyyyy)`
| Entrada | Saída |
|---|---|
| `"22/04/2026"` | `"2026-04-22"` |
### `getAlternativeDate(String paddedDate)`
| Entrada | Saída |
|---|---|
| `"01/04/2026"` | `"1/4/2026"` |
> Estes métodos existem porque os dados no Firestore podem ter formatos de data inconsistentes.
---
## Diagrama de Fluxo
```mermaid
graph TD
A[onCreate] --> B[Configurar CalendarView]
A --> C[Configurar RecyclerView]
A --> D[Carregar consultas de hoje]
B -->|Mudar data| E[loadConsultasForDate]
E --> F{Consultas encontradas?}
F -->|Sim| G[Mostrar lista]
F -->|Não| H[Mostrar 'Sem consultas']
G -->|Aceitar| I[Atualizar status Firestore]
G -->|Eliminar| J[Apagar do Firestore]
G -->|Clicar| K[Abrir DetalhePaciente]
```

44
docs/03_ChatActivity.md Normal file
View File

@@ -0,0 +1,44 @@
# 💬 ChatActivity.java — Chat em Tempo Real
> **Ficheiro:** `app/src/main/java/com/example/medcuida/pro/ChatActivity.java`
> **Layout:** `activity_chat.xml` | **Linhas:** 120
---
## Descrição Geral
Sistema de **chat em tempo real** entre médico e paciente. As mensagens ficam numa **sub-coleção** do Firestore: `consultas/{consultaId}/mensagens/`.
---
## Inicialização (`onCreate`) — Linhas 3978
1. **Verifica autenticação** — se não há utilizador, fecha a Activity
2. **Obtém dados via Intent:**
- `currentUserId` → UID do médico autenticado
- `consultaId` → ID da consulta (recebido da Activity anterior)
3. **Configura RecyclerView** com `setStackFromEnd(true)` (mensagens começam de baixo, como WhatsApp)
4. **Botão enviar** → chama `enviarMensagem()`
---
## `carregarMensagens()` — Linhas 80103
```java
db.collection("consultas").document(consultaId).collection("mensagens")
.orderBy("timestamp", Query.Direction.ASCENDING)
.addSnapshotListener(...)
```
- Escuta em **tempo real** a sub-coleção `mensagens`
- Ordena por `timestamp` (mais antigas primeiro)
- Faz **scroll automático** para a última mensagem
---
## `enviarMensagem()` — Linhas 106118
1. Lê o texto e valida (não envia se vazio)
2. Cria `Mensagem(texto, currentUserId, timestamp)`
3. Adiciona ao Firestore via `.add()`
4. Sucesso → limpa campo | Erro → mostra toast

View File

@@ -0,0 +1,71 @@
# 🏥 DetalhePacienteActivity.java — Detalhes do Paciente
> **Ficheiro:** `app/src/main/java/com/example/medcuida/pro/DetalhePacienteActivity.java`
> **Layout:** `activity_detalhe_paciente.xml` | **Linhas:** 150
---
## Descrição Geral
Mostra os **dados detalhados de um paciente** selecionado, incluindo a sua medicação ativa. Permite abrir o chat com o paciente.
---
## Dados Apresentados
| Campo | Origem Firestore |
|---|---|
| Nome | `utilizadores/{id}.nome_completo` |
| Idade | `utilizadores/{id}.idade` |
| Nº Utente | `utilizadores/{id}.numero_utente` |
| Sexo | `utilizadores/{id}.sexo` |
| Email | `utilizadores/{id}.email` |
| Medicação | Coleção `medicamentos` (filtrada por `userId`) |
---
## Inicialização (`onCreate`) — Linhas 2764
1. **Associa as views** do layout (TextViews + botões)
2. **Recebe via Intent:**
- `PACIENTE_ID` → ID do paciente (obrigatório)
- `CONSULTA_ID` → ID da consulta (opcional, para o chat)
3. **Botão "Sair"**`finish()` (volta à Activity anterior)
4. **Botão "Chat":**
- Se tem `consultaId` → abre chat diretamente
- Se não tem → procura uma consulta existente via `buscarConsultaEParaChat()`
---
## `buscarConsultaEParaChat()` — Linhas 6679
```java
db.collection("consultas")
.whereEqualTo("pacienteId", pacienteId)
.limit(1)
.get()
```
- Procura uma consulta associada ao paciente
- Se encontrar → abre o `ChatActivity` com o `consultaId`
- Se não encontrar → mostra aviso "Não existe consulta ativa"
---
## `carregarDadosPaciente()` — Linhas 88148
### Parte 1: Dados pessoais (Linhas 89111)
- Lê o documento do paciente em `utilizadores/{pacienteId}`
- Preenche nome, idade, nº utente, sexo e email
- Campos nulos aparecem como `"N/D"`
### Parte 2: Medicação (Linhas 113138)
```java
db.collection("medicamentos")
.whereEqualTo("userId", pacienteId)
.get()
```
- Pesquisa na coleção `medicamentos` todos os registos do paciente
- Suporta nomes de campos em **PT** (`nome`, `hora`) e **EN** (`name`, `time`)
- Formata como lista: `• Paracetamol (08:00)`
- Se não houver medicação → mostra "Nenhuma medicação ativa"

View File

@@ -0,0 +1,66 @@
# ✏️ EditarPerfilActivity.java — Edição do Perfil
> **Ficheiro:** `app/src/main/java/com/example/medcuida/pro/EditarPerfilActivity.java`
> **Layout:** `activity_editar_perfil.xml` | **Linhas:** 125
---
## Descrição Geral
Permite ao médico **editar os seus dados pessoais**: nome, especialidade e género. As alterações são guardadas **simultaneamente** nas coleções `utilizadores` e `medicos` do Firestore.
---
## Campos Editáveis
| Campo | Tipo de Input | Obrigatório |
|---|---|---|
| Nome completo | `TextInputEditText` | ✅ Sim |
| Especialidade | `TextInputEditText` | ✅ Sim |
| Género | `AutoCompleteTextView` (dropdown) | Não |
| Email | `TextInputEditText` (só leitura) | — |
---
## Inicialização (`onCreate`) — Linhas 3259
1. Verifica autenticação — se não há utilizador, fecha a Activity
2. Associa as views do layout
3. Configura o **dropdown de género** com 3 opções: `Masculino`, `Feminino`, `Outro`
4. **Botão Voltar**`finish()`
5. **Botão Guardar**`guardarAlteracoes()`
6. Chama `carregarDados()` para preencher os campos atuais
---
## `carregarDados()` — Linhas 7183
```java
db.collection("utilizadores").document(currentUserId).get()
```
- Lê o documento do médico na coleção `utilizadores`
- Preenche os campos: `nome_completo`, `especialidade`, `email`, `sexo`
- Em caso de erro → mostra toast
---
## `guardarAlteracoes()` — Linhas 86123
### Validações (Linhas 8799)
- Nome não pode estar vazio
- Especialidade não pode estar vazia
### Gravação (Linhas 101122)
```java
Map<String, Object> updates = new HashMap<>();
updates.put("nome_completo", name);
updates.put("especialidade", specialty);
updates.put("sexo", gender);
```
1. Desativa o botão para evitar duplo clique
2. Atualiza na coleção `utilizadores`
3. **Também atualiza em `medicos`** para manter sincronizado
4. Sucesso → mostra toast + `finish()`
5. Erro → reativa o botão

View File

@@ -0,0 +1,52 @@
# 👤 PerfilMedicoActivity.java — Perfil do Médico
> **Ficheiro:** `app/src/main/java/com/example/medcuida/pro/PerfilMedicoActivity.java`
> **Layout:** `activity_perfil_medico.xml` | **Linhas:** 110
---
## Descrição Geral
Ecrã de **visualização do perfil do médico**. Mostra nome, email, especialidade e cédula profissional. Inclui botões para editar dados e fazer logout.
---
## Dados Apresentados
| Campo | Fonte Firestore | Fallback |
|---|---|---|
| Nome | `nome_completo` | `nome` |
| Email | `email` | — |
| Especialidade | `especialidade` | `"--"` |
| Cédula | `cedula_profissional` | `cedula``"Não configurada"` |
---
## Inicialização (`onCreate`) — Linhas 2466
1. Associa views e inicializa Firebase
2. **Botão "Editar Dados"** → abre `EditarPerfilActivity`
3. **Bottom Navigation** com 3 tabs (Agenda, Pacientes, Perfil)
4. **Botão Logout:**
```java
mAuth.signOut();
intent.addFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK);
```
- Faz sign out do Firebase
- Limpa toda a pilha de Activities (o utilizador não pode voltar atrás)
---
## `carregarPerfil()` — Linhas 7491
Chamado no `onResume()` (atualiza sempre que o ecrã fica visível).
**Estratégia de busca com fallback:**
1. Tenta na coleção `utilizadores`
2. Se não existir → tenta na coleção `medicos`
---
## `mostrarDados(DocumentSnapshot)` — Linhas 94108
Preenche a UI com os dados do documento Firestore, suportando múltiplos nomes de campos para compatibilidade.

68
docs/07_Models.md Normal file
View File

@@ -0,0 +1,68 @@
# 📦 Models — Classes de Dados
> **Pasta:** `app/src/main/java/com/example/medcuida/pro/models/`
Estas classes representam os **objetos de dados** (POJOs) usados em toda a aplicação. São compatíveis com o Firestore — cada uma tem um construtor vazio obrigatório e getters/setters.
---
## Consulta.java (29 linhas)
Representa uma **consulta médica agendada**.
| Campo | Tipo | Descrição |
|---|---|---|
| `id` | `String` | ID do documento Firestore |
| `data` | `String` | Data da consulta (ex: `"22/04/2026"`) |
| `hora` | `String` | Hora da consulta (ex: `"14:30"`) |
| `medicos` | `Object` | ID(s) do(s) médico(s) — pode ser `String` ou `List<String>` |
| `pacienteId` | `String` | ID do paciente associado |
| `pacienteNome` | `String` | Nome do paciente (para exibição rápida) |
| `status` | `String` | Estado: `"Pendente"`, `"aceite"`, `"cancelada"` |
> ⚠️ O campo `medicos` é do tipo `Object` porque no Firestore pode ser guardado como String simples ou como Array, dependendo de como foi criado.
---
## Medico.java (61 linhas)
Representa um **médico** registado na aplicação.
| Campo | Tipo | Descrição |
|---|---|---|
| `id` | `String` | UID do Firebase Auth |
| `nome` | `String` | Nome completo |
| `email` | `String` | Email de login |
| `especialidade` | `String` | Especialidade médica |
| `genero` | `String` | Género (`Masculino`, `Feminino`, `Outro`) |
Tem **dois construtores**: vazio (para Firestore) e completo (para criação manual).
---
## Mensagem.java (42 linhas)
Representa uma **mensagem de chat** entre médico e paciente.
| Campo | Tipo | Descrição |
|---|---|---|
| `texto` | `String` | Conteúdo da mensagem |
| `senderId` | `String` | UID de quem enviou |
| `timestamp` | `long` | Hora de envio em milissegundos (epoch) |
Guardada na sub-coleção `consultas/{id}/mensagens/`.
---
## Paciente.java (20 linhas)
Representa um **paciente** da aplicação.
| Campo | Tipo | Descrição |
|---|---|---|
| `id` | `String` | ID do documento Firestore |
| `nome` | `String` | Nome do paciente |
| `email` | `String` | Email do paciente |
| `fotoUrl` | `String` | URL da foto de perfil (se existir) |
> É a classe mais simples — os dados adicionais (idade, sexo, nº utente) são lidos diretamente do Firestore no `DetalhePacienteActivity`.

102
docs/08_Adapters.md Normal file
View File

@@ -0,0 +1,102 @@
# 🔄 Adapters — Adaptadores RecyclerView
> **Pasta:** `app/src/main/java/com/example/medcuida/pro/ui/adapters/`
Os Adapters fazem a ligação entre os **dados** (listas de objetos) e as **views** (itens visuais no RecyclerView). Cada adapter tem um `ViewHolder` interno que mapeia os elementos do layout XML.
---
## ConsultaAdapter.java (113 linhas)
**Layout do item:** `item_consulta_medico.xml`
### Para que serve
Mostra cada consulta na lista da agenda com: nome do paciente, data/hora, status e botões de ação.
### Interfaces (callbacks)
```java
interface OnConsultaActionClickListener {
void onAceitarClick(Consulta consulta); // Botão "Confirmar"
void onEliminarClick(Consulta consulta); // Botão "Cancelar"
}
interface OnConsultaClickListener {
void onConsultaClick(Consulta consulta); // Clique no item inteiro
}
```
### Lógica do `bind()` (Linhas 75109)
1. **Nome do paciente** → mostra `pacienteNome` ou `"Desconhecido"`
2. **Data e hora** → combina `data` + `hora` (ex: `"22/04/2026 às 14:30"`)
3. **Status** → mostra o texto do status atual
4. **Botão Confirmar:**
- Visível **apenas** se o status for `"Pendente"`
- Chama `onAceitarClick()` ao clicar
5. **Botão Cancelar:**
- **Sempre visível**
- Chama `onEliminarClick()` ao clicar
6. **Clique no item** → chama `onConsultaClick()`
---
## MensagemAdapter.java (74 linhas)
**Layout do item:** `item_mensagem.xml`
### Para que serve
Mostra cada mensagem no chat. Distingue visualmente mensagens **enviadas** vs **recebidas**.
### Como funciona (Linhas 4053)
```java
if (mensagem.getSenderId().equals(currentUserId)) {
// Mostrar layout de mensagem ENVIADA (direita)
} else {
// Mostrar layout de mensagem RECEBIDA (esquerda)
}
```
- Cada item tem **dois layouts** (`layout_msg_enviada` e `layout_msg_recebida`)
- Apenas um fica visível de cada vez, com base no `senderId`
- O `currentUserId` é passado no construtor
---
## PacienteAdapter.java (75 linhas)
**Layout do item:** `item_paciente.xml`
### Para que serve
Mostra cada paciente numa lista simples com nome e email.
### Interface
```java
interface OnPacienteClickListener {
void onPacienteClick(Paciente paciente);
}
```
### Lógica do `bind()` (Linhas 6372)
1. **Nome** → mostra `nome` ou `"Desconhecido"`
2. **Email** → mostra `email` ou `"N/A"`
3. **Clique no item** → chama `onPacienteClick()`
---
## Padrão Comum dos 3 Adapters
Todos seguem a mesma estrutura:
```
1. Extends RecyclerView.Adapter<ViewHolder>
2. Lista interna de dados
3. Método setXxx(List) para atualizar + notifyDataSetChanged()
4. onCreateViewHolder → infla o layout XML
5. onBindViewHolder → preenche os dados
6. getItemCount → retorna tamanho da lista
7. ViewHolder interno (static class)
```

107
docs/09_Autenticacao.md Normal file
View File

@@ -0,0 +1,107 @@
# 🔐 Autenticação — Login e Registo
> **Pasta:** `app/src/main/java/com/example/medcuida/pro/ui/auth/`
---
## LoginActivity.java (154 linhas)
> **Layout:** `activity_login.xml`
### Descrição
Ecrã de **entrada na aplicação**. Permite login com email/password via Firebase Auth.
### Inicialização (`onCreate`) — Linhas 3478
1. **Auto-login:** Se já existe sessão ativa → redireciona direto para `MainActivity`
2. **Campos:** email e password (`TextInputEditText`)
3. **Botão "Entrar"**`attemptLogin()`
4. **Link "Registar"** → abre `RegisterActivity`
5. **Link "Esqueci password":**
- Valida se o email foi preenchido
- Envia email de recuperação via `mAuth.sendPasswordResetEmail()`
### `attemptLogin()` — Linhas 8198
Validações antes de enviar ao Firebase:
- Email não pode estar vazio
- Password não pode estar vazia
### `loginUser()` — Linhas 100123
```java
mAuth.signInWithEmailAndPassword(email, password)
```
1. Desativa o botão (evita duplo clique) e mostra "A entrar..."
2. Se login OK → chama `checkUserAccess()`
3. Se falhar → mostra mensagem de erro e reativa o botão
### `checkUserAccess()` — Linhas 125152
**Verifica se o utilizador tem perfil configurado** (estratégia com fallback):
```
1º → Procura em 'medicos' → Se existe → Entrar na app
2º → Procura em 'utilizadores' → Se existe → Entrar na app
3º → Não encontrado → Erro + signOut
```
Se não encontrar em nenhuma coleção → faz `signOut()` e pede para registar.
---
## RegisterActivity.java (187 linhas)
> **Layout:** `activity_register_medico.xml`
### Descrição
Ecrã de **registo de novos médicos**. Cria conta no Firebase Auth e guarda dados no Firestore.
### Campos do Formulário
| Campo | Tipo | Obrigatório | Validação |
|---|---|---|---|
| Nome completo | `TextInputEditText` | ✅ | Não vazio |
| Especialidade | `TextInputEditText` | ✅ | Não vazio |
| Género | `AutoCompleteTextView` | ✅ | Não vazio |
| Email | `TextInputEditText` | ✅ | Não vazio |
| Password | `TextInputEditText` | ✅ | Mínimo 6 caracteres |
### `attemptRegister()` — Linhas 75118
Valida todos os campos sequencialmente. Se algum falhar, faz `requestFocus()` nesse campo.
### `registerUser()` — Linhas 121155
```java
mAuth.createUserWithEmailAndPassword(email, password)
```
1. Desativa o botão de registo
2. Se criar conta OK → chama `saveMedicoData()`
3. **Caso especial — email já existe:**
- Tenta fazer login com as credenciais fornecidas
- Se login OK → grava os dados (pode ter falhado antes)
- Se login falhar → mostra erro "email já registado"
### `saveMedicoData()` — Linhas 157185
Grava os dados do médico em **duas coleções** para compatibilidade:
```java
Map<String, Object> medicoMap = new 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");
```
| Coleção | Documento |
|---|---|
| `utilizadores/{uid}` | Dados principais |
| `medicos/{uid}` | Cópia para compatibilidade |
Após gravar com sucesso → redireciona para `MainActivity`.

View File

@@ -0,0 +1,98 @@
# ⚙️ Configuração Gradle — Build do Projeto
> **Ficheiros:** `build.gradle` (raiz), `app/build.gradle`, `settings.gradle`
---
## settings.gradle
Define o **nome do projeto** e os **repositórios** de onde são descarregadas as dependências.
```gradle
rootProject.name = "Cuida"
include ':app'
```
| Repositório | Finalidade |
|---|---|
| `google()` | Bibliotecas Android e Firebase |
| `mavenCentral()` | Bibliotecas Java/Kotlin gerais |
| `jitpack.io` | Bibliotecas de projetos GitHub |
---
## build.gradle (raiz)
Define os **plugins globais** e as suas versões.
| Plugin | Versão | Finalidade |
|---|---|---|
| `com.android.application` | 9.2.0 | Compilação de apps Android |
| `com.android.library` | 9.2.0 | Compilação de bibliotecas Android |
| `com.google.gms.google-services` | 4.4.4 | Integração com Firebase |
---
## app/build.gradle
Configuração principal da aplicação.
### Identificação da App
| Propriedade | Valor |
|---|---|
| `namespace` | `com.example.medcuida.pro` |
| `applicationId` | `com.example.medcuida.pro` |
| `compileSdk` | 35 |
| `minSdk` | 24 (Android 7.0) |
| `targetSdk` | 35 |
| `versionCode` | 1 |
| `versionName` | `"1.0"` |
| Java | 1.8 |
| View Binding | ✅ Ativado |
### Dependências Organizadas por Categoria
#### 🎨 Interface (UI)
| Dependência | Versão | Uso |
|---|---|---|
| `appcompat` | 1.6.1 | Compatibilidade com versões antigas do Android |
| `material` | 1.11.0 | Componentes Material Design (botões, cards, nav) |
| `constraintlayout` | 2.1.4 | Layouts flexíveis e responsivos |
| `navigation-fragment` | 2.7.7 | Navegação entre fragments |
| `navigation-ui` | 2.7.7 | UI de navegação |
#### 🔥 Firebase
| Dependência | Versão | Uso |
|---|---|---|
| `firebase-bom` | 32.7.2 | Gestão de versões Firebase (Bill of Materials) |
| `firebase-auth` | via BoM | Autenticação (email/password) |
| `firebase-firestore` | via BoM | Base de dados NoSQL em tempo real |
#### 🤖 IA e Rede
| Dependência | Versão | Uso |
|---|---|---|
| `generativeai` | Última | Google Gemini AI SDK |
| `guava` | 31.1 | Operações assíncronas (Futures) |
| `retrofit` | 2.9.0 | Chamadas HTTP tipadas |
| `converter-gson` | 2.9.0 | Conversão JSON ↔ objetos Java |
| `okhttp` | 4.10.0 | Cliente HTTP base |
#### 🔑 Autenticação Avançada
| Dependência | Versão | Uso |
|---|---|---|
| `credentials` | 1.5.0 | API de credenciais Android |
| `credentials-play-services-auth` | 1.5.0 | Google Sign-In via Credentials |
| `googleid` | 1.1.1 | Google Identity |
#### 📍 Localização
| Dependência | Versão | Uso |
|---|---|---|
| `play-services-location` | 21.0.1 | Serviços de localização GPS |
#### 🧪 Testes
| Dependência | Versão | Uso |
|---|---|---|
| `junit` | 4.13.2 | Testes unitários |
| `ext:junit` | 1.1.5 | Testes instrumentados |
| `espresso-core` | 3.5.1 | Testes de UI |

156
docs/11_Layouts_XML.md Normal file
View File

@@ -0,0 +1,156 @@
# 🎨 Layouts XML — Interfaces Visuais
> **Pasta:** `app/src/main/res/layout/`
---
## Layouts de Activity (ecrãs completos)
### `activity_main.xml` (243 linhas)
**Usado por:** `MainActivity.java`
Estrutura principal com 3 secções controladas pela BottomNav:
| Secção | ID | Descrição |
|---|---|---|
| Header | `lay_top` | Saudação "Olá, [Nome]" (`tv_greeting_main`) |
| Agenda | `view_agenda` | CalendarView num MaterialCard + RecyclerView de consultas + texto "agenda vazia" |
| Pacientes | `view_pacientes` | RecyclerView de pacientes (`recycler_consultas`) + texto "vazio" |
| Perfil | `view_perfil` | Ícone de utilizador + MaterialCard com dados + botões "Editar" e "Logout" |
| Nav | `bottom_navigation` | BottomNavigationView com menu `menu_bottom` |
**Layout raiz:** `RelativeLayout` com fundo `#F5F5F5`
---
### `activity_agenda.xml` (53 linhas)
**Usado por:** `AgendaActivity.java`
Layout vertical simples:
1. `CalendarView` — calendário nativo
2. `TextView` — título "Consultas agendadas:"
3. `RecyclerView` (`recycler_agenda`) — lista de consultas
4. `TextView` (`text_agenda_vazia`) — mensagem quando vazio (visibility: gone)
5. `BottomNavigationView` — navegação inferior
---
### `activity_chat.xml` (57 linhas)
**Usado por:** `ChatActivity.java`
**Layout:** `ConstraintLayout`
| Elemento | ID | Descrição |
|---|---|---|
| RecyclerView | `recycler_mensagens` | Ocupa o espaço todo acima do input |
| Barra de input | `layout_input` | LinearLayout horizontal no fundo |
| Campo de texto | `et_mensagem_input` | EditText com hint "Escrever mensagem..." |
| Botão enviar | `btn_enviar` | ImageButton com ícone `ic_send` |
---
### `activity_login.xml` (127 linhas)
**Usado por:** `LoginActivity.java`
Layout num `ScrollView` centrado:
1. **Logo** — ImageView 250×250dp (`logo_app`)
2. **Card de login** — MaterialCardView contendo:
- Título "Iniciar Sessão"
- Campo email (`email_edit_text`)
- Campo password (`password_edit_text`)
- Checkbox "Lembrar-me"
- Botão "Entrar" (`login_button`)
- Link "Esqueceu a palavra-passe" (`forgot_password_link`)
3. **Link de registo** — "Não tem conta? Registar" (`register_link`)
---
### `activity_register_medico.xml` (153 linhas)
**Usado por:** `RegisterActivity.java`
Layout num `ScrollView`:
1. **Logo** — ImageView 200×200dp (`ic_logo`)
2. **Card de registo** — MaterialCardView contendo:
- Título "Registar"
- Campo nome (`name_edit_text`)
- Campo especialidade (`specialty_edit_text`)
- Dropdown género (`gender_auto_complete`)
- Campo email (`email_edit_text`)
- Campo password (`password_edit_text`)
- Botão "Registar" (`register_button`)
- Link "Já tem conta? Entrar" (`login_link`)
---
### `activity_detalhe_paciente.xml` (158 linhas)
**Usado por:** `DetalhePacienteActivity.java`
**Layout:** `ConstraintLayout`
| Secção | Conteúdo |
|---|---|
| Topo | Botão voltar (`btn_sair_detalhe`) com ícone seta |
| Card "Informação Pessoal" | Nome, idade, nº utente, sexo, email |
| Card "Medicação Atual" | Lista de medicação (`tv_medicacao_paciente`) |
| Fundo | Botão "Conversar com Paciente" (`btn_chat_paciente`) com ícone chat |
---
### `activity_editar_perfil.xml` (103 linhas)
**Usado por:** `EditarPerfilActivity.java`
Layout num `ScrollView`:
1. Botão voltar (`btn_voltar`)
2. Título "Editar Dados Pessoais"
3. Campo nome (`edit_name`)
4. Campo especialidade (`edit_specialty`)
5. Dropdown sexo (`edit_gender`) — `ExposedDropdownMenu`
6. Campo email (`edit_email`) — **desativado** (não editável)
7. Botão "GUARDAR ALTERAÇÕES" (`btn_guardar_alteracoes`)
---
### `activity_perfil_medico.xml` (125 linhas)
**Usado por:** `PerfilMedicoActivity.java`
Layout vertical com:
1. Ícone de utilizador (100×100dp)
2. MaterialCard com dados do médico (nome, email, especialidade, cédula)
3. Botão "EDITAR DADOS" (preto)
4. Botão "TERMINAR SESSÃO" (contorno vermelho)
5. BottomNavigationView
---
## Layouts de Item (para RecyclerView)
### `item_consulta_medico.xml` (101 linhas)
**Usado por:** `ConsultaAdapter.java`
MaterialCard com cantos arredondados (16dp):
- **Linha superior:** Ícone do utente (circle_bg) + nome + data/hora + status
- **Linha inferior:** Botão "Eliminar" (vermelho, outlined) + Botão "Aceitar" (preenchido)
---
### `item_mensagem.xml` (51 linhas)
**Usado por:** `MensagemAdapter.java`
Cada item tem **dois layouts** (apenas um visível de cada vez):
| Layout | ID | Posição | Estilo |
|---|---|---|---|
| Recebida | `layout_msg_recebida` | Esquerda | `bg_bubble_receive` (texto preto) |
| Enviada | `layout_msg_enviada` | Direita | `bg_bubble_send` (texto branco) |
Largura máxima: 280dp (para não ocupar o ecrã todo)
---
### `item_paciente.xml` (59 linhas)
**Usado por:** `PacienteAdapter.java`
MaterialCard simples com:
- Ícone do paciente (circle_bg, 56×56dp)
- Nome em negrito (18sp)
- Email em cinza (14sp)

View File

@@ -0,0 +1,143 @@
# 🎨 Layouts Adicionais e Recursos — Fragments, Dialogs e Drawables
> **Pasta:** `app/src/main/res/layout/` e `app/src/main/res/drawable/`
---
## Layouts de Activity (extras)
### `activity_forgot_password.xml` (64 linhas)
Ecrã de **recuperação de palavra-passe**:
- Logo da app (187×177dp)
- Título "Esqueceu a palavra-passe"
- Texto explicativo
- Campo email (`email_edit_text`)
- Botão "Recuperar Palavra-passe" (`reset_button`)
- Link "Voltar ao Login" (`back_to_login`)
### `activity_register.xml` (8607 bytes)
Layout alternativo de registo (versão paciente). Similar ao `activity_register_medico.xml` mas sem campos de especialidade médica.
---
## Layouts de Dialog (pop-ups)
### `dialog_add_medication.xml` (86 linhas)
**Diálogo para adicionar medicamento:**
| Campo | ID | Tipo |
|---|---|---|
| Nome do medicamento | `edit_med_name` | TextInputEditText |
| Horário | `text_med_time` | TextView (mostra hora, ex: "08:00") |
| Via de administração | `radio_group_route` | RadioGroup com 3 opções |
| Notas | `edit_med_notes` | TextInputEditText (multilinha) |
**Opções de via de administração:**
- Via Oral (Pela boca)
- Via Tópica (Na pele)
- Via Inalatória (Pelo nariz/boca)
### `dialog_change_password.xml` (52 linhas)
**Diálogo para alterar palavra-passe:**
- Título "Alterar Palavra-passe"
- Campo "Nova Palavra-passe" (`new_password`)
- Botões: "Cancelar" (`button_cancel_password`) + "Salvar" (`button_save_password`)
### `dialog_edit_profile.xml` (129 linhas)
**Diálogo para editar perfil do paciente:**
- Foto de perfil circular (`edit_profile_image`) com botão "Mudar Foto"
- Campos: Nome, Idade (máx 3 chars), Nº Utente (máx 9 chars), Email
- Botão "Alterar Palavra-passe" (`button_change_password`)
- Botões: "Cancelar" + "Salvar"
---
## Layouts de Fragment
### `fragment_home.xml` (76 linhas)
**Ecrã inicial do paciente:**
- Saudação "Olá, utilizador!" (`text_greeting`)
- Card "Próxima Medicação" (`card_next_medication`) com nome e hora
- Botão "Marcar Consulta" (`button_book_appointment`)
### `fragment_medication.xml` (55 linhas)
**Gestão de medicamentos do paciente:**
- Título "Medicação"
- RecyclerView (`recycler_medication`) — lista de medicamentos
- Texto "Ainda não tem medicamentos" (`text_empty_medications`)
- FAB "+" (`fab_add_medication`) — botão flutuante para adicionar
### `fragment_profile.xml` (128 linhas)
**Perfil do paciente:**
- Foto de perfil circular (`profile_image`)
- Card com: Nome, Email, Idade, Nº Utente
- Botão "Editar Dados" (`button_edit_profile`)
- Botão "Terminar Sessão" (`button_logout`) — contorno vermelho
### `fragment_sns24.xml` (93 linhas)
**Módulo SNS 24 com IA:**
- Título "SNS 24"
- Botão "Ligar SNS 24 (808 24 24 24)" (`button_call_sns`) — verde
- Secção "Triagem com Inteligência Artificial":
- Campo de sintomas (`input_symptoms`) — multilinha
- Botão "Analisar Sintomas" (`button_ai_triage`)
- Resultado da IA (`text_ai_result`) — inicialmente escondido
- Botão "Hospital mais próximo" (`button_find_hospital`) — vermelho, escondido
### `fragment_appointments.xml` (1740 bytes)
Layout para lista de consultas do paciente com RecyclerView.
### `fragment_schedule_appointment.xml` (3421 bytes)
Layout para agendar novas consultas.
---
## Layouts de Item (RecyclerView extras)
### `item_appointment.xml` (2163 bytes)
Card para cada consulta na lista do paciente.
### `item_medication.xml` (2841 bytes)
Card para cada medicamento na lista de medicação.
### `item_time_slot.xml` (421 bytes)
Slot de horário para agendamento de consultas.
---
## Drawables (Recursos Visuais)
### Fundos e Shapes
| Ficheiro | Descrição |
|---|---|
| `bg_bubble_send.xml` | Fundo da bolha de mensagem **enviada** (cor primária, cantos arredondados) |
| `bg_bubble_receive.xml` | Fundo da bolha de mensagem **recebida** (cinza claro, cantos arredondados) |
| `bg_chat_input.xml` | Fundo do campo de texto do chat (bordas arredondadas) |
| `circle_bg.xml` | Fundo circular para ícones de utilizador |
| `btn_outline_error.xml` | Estilo de botão com contorno vermelho (erro) |
| `btn_outline_primary.xml` | Estilo de botão com contorno primário |
### Ícones
| Ficheiro | Descrição |
|---|---|
| `ic_arrow_back.xml` | Seta para voltar (←) |
| `ic_chat.xml` | Ícone de chat/conversa |
| `ic_send.xml` | Ícone de enviar mensagem |
| `ic_user.xml` | Ícone de utilizador/pessoa |
| `ic_placeholder.xml` | Placeholder para fotos de perfil |
| `ic_nav_agenda.xml` | Ícone da tab Agenda |
| `ic_nav_pacientes.xml` | Ícone da tab Pacientes |
| `ic_nav_contactos.xml` | Ícone da tab Contactos |
| `ic_nav_inicio.xml` | Ícone da tab Início |
### Logos e Launcher
| Ficheiro | Descrição |
|---|---|
| `ic_logo.png` | Logo da aplicação (83KB) |
| `logo_app.png` | Logo para o ecrã de login (23KB) |
| `ic_launcher.xml` | Ícone do launcher (adaptive icon) |
| `ic_launcher_round.xml` | Ícone redondo do launcher |
| `ic_logo_scaled.xml` | Logo escalada para diferentes tamanhos |

View File

@@ -0,0 +1,40 @@
# 📄 Análise de Código: `MainActivity.java`
O `MainActivity.java` é a classe central da aplicação. Como usa o `BottomNavigationView`, ele controla três "ecrãs" virtuais que se escondem ou aparecem dependendo do botão carregado: Agenda, Pacientes e Perfil.
## 1. Importações e Declarações (Linhas 1 - 34)
A classe estende `AppCompatActivity` e implementa interfaces do `ConsultaAdapter` (`OnConsultaActionClickListener`, `OnConsultaClickListener`) para conseguir "ouvir" cliques feitos nos itens da lista de consultas.
## 2. Variáveis Globais (Linhas 36 - 57)
* **Views de Navegação:** `viewAgenda`, `viewPacientes`, `viewPerfil`, `layTop` — Estas variáveis controlam a visibilidade de cada secção da app.
* **RecyclerViews e Adapters:** `recyclerConsultas` e `adapterPacientes` (para a lista de pacientes), `recyclerAgenda` e `adapterAgenda` (para a lista de consultas).
* **Firebase:** `mAuth` (autenticação) e `db` (Firestore).
* **ID:** `currentMedicoId` guarda o UID (User ID) do médico logado.
## 3. Método `onCreate()` (Linhas 59 - 188)
* **Verificação de Login:** A primeira coisa que o `onCreate` faz é verificar se há algum utilizador logado (`mAuth.getCurrentUser() == null`). Se não houver, ele atira o utilizador para a `LoginActivity`.
* **Carregamento Instantâneo (SharedPreferences):** Usa o cache local `SessaoMedico` para exibir o nome ("Olá, [Nome]") antes mesmo da base de dados responder.
* **Configuração dos Recyclers:** Define os layouts (LinearLayoutManager) e os Adapters que vão desenhar as listas.
* **Bottom Navigation:** Há um `setOnItemSelectedListener` que, dependendo do botão tocado (Agenda, Pacientes, Perfil), faz um `setVisibility(View.GONE)` aos ecrãs indesejados e um `VISIBLE` ao ecrã selecionado.
* **Início dos Dados:** Chama `loadUtilizadores()`, `loadPerfilMedico()`, e usa a data atual (`SimpleDateFormat`) para chamar `loadConsultasAgendaForDate(today)`.
## 4. Lógica de Pacientes (`loadUtilizadores()`) (Linhas 190 - 230)
* Coloca um `SnapshotListener` (espião em tempo real) na coleção `"utilizadores"`.
* Se o `tipo` for "paciente" (ou nulo), adiciona à lista e manda o adapter desenhá-los no ecrã.
* Tenta ir buscar o nome a `"nome_completo"` e depois a `"nome"`.
## 5. Eventos de Clique nas Consultas (Linhas 232 - 260)
* **`onAceitarClick()`:** Altera o status da consulta para "aceite".
* **`onEliminarClick()`:** Elimina a consulta inteira da base de dados e informa o utilizador com um Toast.
* **`onConsultaClick()`:** Se o médico clicar na consulta (e não nos botões de aceitar/rejeitar), a app vai para a `DetalhePacienteActivity`, passando o `PACIENTE_ID` via Intent.
## 6. Lógica da Agenda (`loadConsultasAgendaForDate()`) (Linhas 262 - 342)
* Recebe uma data (ex: `12/04/2026`).
* Liga-se à coleção `"consultas"`. Filtra no cliente (através de um `if`) se o ID do médico (como string ou como parte de uma lista) está na consulta.
* Aceita três formatos de data via `getAlternativeDate` (ex: 04/05/2026 e 4/5/2026) ou formato ISO.
* Só mostra consultas se não estiverem marcadas como "cancelada".
## 7. Lógica do Perfil (`loadPerfilMedico()`) (Linhas 350 - 403)
* Acede à coleção `"utilizadores"`. Se o documento não existir, faz um *fallback* e tenta ler na coleção `"medicos"`.
* Depois de encontrar, usa o `updateProfileUI()` para meter o nome, email, especialidade e cédula nos `TextViews` respetivos.
* Atualiza a `SharedPreferences` para garantir que o "Olá, X" nunca fica vazio quando o ecrã recarrega.

View File

@@ -0,0 +1,30 @@
# 📄 Análise de Código: `LoginActivity.java`
Esta classe (`app/src/main/java/com/example/medcuida/pro/ui/auth/LoginActivity.java`) gere toda a entrada do médico no sistema.
## 1. Importações e Declarações (Linhas 1 - 33)
Importa elementos do Firebase (`FirebaseAuth`, `FirebaseUser`, `FirebaseFirestore`) e componentes da interface (`TextInputEditText`, `MaterialButton`).
## 2. Inicialização `onCreate()` (Linhas 34 - 79)
* **Instâncias Firebase:** `mAuth` e `db` são inicializados.
* **Proteção de Sessão:** Se `mAuth.getCurrentUser() != null`, significa que o utilizador já está logado. Ele nem sequer abre o ecrã; avança logo para a `MainActivity`.
* **Ligações da Interface:** Mapeia botões (Login) e links (Registo, Recuperação de Pass) aos IDs do ficheiro XML.
* **Botão Recuperar Password:** Se carregado, verifica se o campo do email não está vazio. Se estiver cheio, chama `mAuth.sendPasswordResetEmail(email)`.
## 3. Tentativa de Login `attemptLogin()` (Linhas 81 - 98)
* Puxa o texto dos inputs `emailEditText` e `passwordEditText`.
* Valida os campos: se um deles estiver vazio, dá erro (`setError`) e foca o campo.
* Passa as credenciais para o `loginUser()`.
## 4. O Método `loginUser()` (Linhas 100 - 123)
* **Experiência de Utilizador (UX):** Bloqueia o botão e muda o texto para "A entrar..." (assim evita que o médico clique duas vezes).
* Faz a chamada ao Firebase: `mAuth.signInWithEmailAndPassword()`.
* **Se Sucesso:** Pega no UID gerado e atira-o para o `checkUserAccess()`.
* **Se Falha:** Mostra a mensagem de erro (Ex: "Password errada") e reativa o botão de login.
## 5. Validação de Papel (Role) `checkUserAccess()` (Linhas 125 - 153)
Como a base de dados tem tanto pacientes como médicos, este método é crucial para garantir que um "paciente" não entra na app dos médicos por engano.
1. Tenta ler o documento do utilizador na coleção `"medicos"`.
2. Se existir, é um médico; vai para a `MainActivity`.
3. Se não existir, tenta ler na coleção `"utilizadores"`. Isto acontece porque em versões antigas/outras ramificações da app, os médicos também podem estar aí registados.
4. Se também não estiver aí, avisa "Esta conta não tem perfil configurado" e **faz sign out** imediatamente, forçando o ecrã a ficar no Login.

View File

@@ -0,0 +1,26 @@
# 📄 Análise de Código: `AgendaActivity.java`
O ficheiro `app/src/main/java/com/example/medcuida/pro/AgendaActivity.java` é usado como o ecrã de Calendário/Agenda em "ecrã inteiro", embora a `MainActivity` também incorpore parte desta vista. O objetivo primário é ver as consultas de um dia específico.
## 1. Variáveis e `onCreate()` (Linhas 28 - 94)
* Tem um `CalendarView` e uma `RecyclerView` (que vai conter as listas das consultas).
* A lógica do **BottomNavigationView** aqui está alterada: Se clicares em "Pacientes", ele não muda uma View interna (como faz na `MainActivity`); aqui, ele lança de facto um `Intent` para voltar para a `MainActivity`. Se clicares em "Perfil", ele lança a `PerfilMedicoActivity`.
* Configura o `ConsultaAdapter`. Tem "listeners" para Aceitar, Eliminar ou Clicar (abre `DetalhePacienteActivity`).
## 2. Gestão do Calendário (Linhas 87 - 93)
* A app usa um `SimpleDateFormat` no formato `dd/MM/yyyy` para saber o dia atual.
* O `calendarView.setOnDateChangeListener` é acionado sempre que o médico toca num dia no ecrã. Ele refaz a string da data e chama `loadConsultasForDate(selectedDate)`.
## 3. Pesquisa de Consultas `loadConsultasForDate()` (Linhas 96 - 153)
* Retira a subscrição antiga (`agendaListener.remove()`) para não ficar com múltiplas consultas de dados abertas na memória.
* Lê na coleção `"consultas"`.
* Em vez de fazer uma "Query" no Firestore por data, ele lê quase toda a coleção e **filtra localmente** no telemóvel (dentro do `for(QueryDocumentSnapshot doc : value)`).
* Verifica se o id do médico logado (`doctorId`) está dentro do atributo `medicos` da consulta (que pode ser uma String solta ou uma Lista de Strings).
* Depois, tenta ver se a data coincide. Se a consulta for cancelada, é ignorada.
## 4. Lógica de Alteração da Consulta (Linhas 155 - 171)
* **`aceitarConsulta()`**: Pega no ID do documento e faz `.update("status", "aceite")`. O Firestore notifica o telemóvel de imediato graças ao `SnapshotListener`, e a consulta desaparece/muda de estado na lista sem ser necessário recarregar o ecrã.
* **`eliminarConsulta()`**: Faz um `.delete()` duro na consulta.
## 5. Tratamento de Datas Sujas (Linhas 173 - 191)
Estes dois métodos, `convertToISODate()` e `getAlternativeDate()`, existem porque a base de dados pode ter lixo (datas como `4/5/2026` em vez de `04/05/2026`, ou `2026-05-04`). Este bloco garante que, independentemente de quem guardou a consulta, o ecrã mostra o dado na mesma.