esta guardar e nao esta a entar no perfil

This commit is contained in:
2026-03-17 17:08:44 +00:00
parent 1fcd2d0da5
commit 49252c391a
84 changed files with 2109 additions and 1446 deletions

View File

@@ -39,6 +39,22 @@
<activity android:name=".ui.auth.RegisterActivity" />
<activity android:name=".ui.auth.ForgotPasswordActivity" />
<activity android:name=".ui.auth.ResetPasswordActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<!-- Update the host to match your Firebase project's hosting domain
or the custom domain you configured for dynamic links -->
<data
android:scheme="https"
android:host="papcuida.page.link" />
<data
android:scheme="cuida"
android:host="resetpassword" />
</intent-filter>
</activity>
<receiver android:name=".services.AlarmReceiver" android:exported="false" />

View File

@@ -11,14 +11,33 @@ import com.google.common.util.concurrent.ListenableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import com.google.ai.client.generativeai.type.BlockThreshold;
import com.google.ai.client.generativeai.type.HarmCategory;
import com.google.ai.client.generativeai.type.SafetySetting;
import java.util.Arrays;
import java.util.List;
import java.util.Collections;
public class Gemini {
private final GenerativeModelFutures modelo;
public Gemini() {
// 1. Configurar o modelo (usa a tua API Key do Google AI Studio)
// 1. Configurar os SafetySettings para permitir termos médicos e partes do corpo
List<SafetySetting> safetySettings = Arrays.asList(
new SafetySetting(HarmCategory.HARASSMENT, BlockThreshold.NONE),
new SafetySetting(HarmCategory.HATE_SPEECH, BlockThreshold.NONE),
new SafetySetting(HarmCategory.SEXUALLY_EXPLICIT, BlockThreshold.NONE),
new SafetySetting(HarmCategory.DANGEROUS_CONTENT, BlockThreshold.NONE)
);
// 2. Configurar o modelo (usa a tua API Key do Google AI Studio)
GenerativeModel generativeModel = new GenerativeModel(
"gemini-2.5-flash",
"AIzaSyBmLgn-SHaTDvAeDWsw2iTZRR9gahhOu7k");
"AIzaSyBmLgn-SHaTDvAeDWsw2iTZRR9gahhOu7k",
null, // generationConfig
safetySettings
);
this.modelo = GenerativeModelFutures.from(generativeModel);
}

View File

@@ -16,7 +16,7 @@ public class ForgotPasswordActivity extends AppCompatActivity {
setContentView(binding.getRoot());
binding.resetButton.setOnClickListener(v -> {
String email = binding.emailEditText.getText().toString();
String email = binding.emailEditText.getText().toString().trim();
if (email.isEmpty()) {
Toast.makeText(this, "Por favor insira o seu email.", Toast.LENGTH_SHORT).show();
} else {

View File

@@ -0,0 +1,82 @@
package com.example.cuida.ui.auth;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import com.example.cuida.databinding.ActivityResetPasswordBinding;
import com.google.firebase.auth.FirebaseAuth;
public class ResetPasswordActivity extends AppCompatActivity {
private ActivityResetPasswordBinding binding;
private String oobCode;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityResetPasswordBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
// Use custom uri scheme or https scheme, extracting oobCode parameter
Intent intent = getIntent();
if (intent != null && intent.getData() != null) {
Uri data = intent.getData();
oobCode = data.getQueryParameter("oobCode");
if (oobCode == null || oobCode.isEmpty()) {
Toast.makeText(this, "Link de redefinição inválido.", Toast.LENGTH_LONG).show();
finish();
}
} else {
Toast.makeText(this, "Nenhum código de redefinição encontrado.", Toast.LENGTH_LONG).show();
finish();
}
binding.saveNewPasswordButton.setOnClickListener(v -> saveNewPassword());
}
private void saveNewPassword() {
String newPassword = binding.newPasswordEditText.getText().toString();
String confirmPassword = binding.confirmNewPasswordEditText.getText().toString();
if (newPassword.isEmpty() || confirmPassword.isEmpty()) {
Toast.makeText(this, "Preencha ambas as palavras-passe.", Toast.LENGTH_SHORT).show();
return;
}
if (!newPassword.equals(confirmPassword)) {
Toast.makeText(this, "As palavras-passe não coincidem.", Toast.LENGTH_SHORT).show();
return;
}
if (newPassword.length() < 6) {
Toast.makeText(this, "A palavra-passe deve ter pelo menos 6 caracteres.", Toast.LENGTH_SHORT).show();
return;
}
binding.saveNewPasswordButton.setEnabled(false);
binding.saveNewPasswordButton.setText("A guardar...");
FirebaseAuth.getInstance().confirmPasswordReset(oobCode, newPassword)
.addOnCompleteListener(task -> {
if (task.isSuccessful()) {
Toast.makeText(this, "Palavra-passe atualizada com sucesso!", Toast.LENGTH_LONG).show();
// Go back to login screen
Intent intent = new Intent(ResetPasswordActivity.this, LoginActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
finish();
} else {
binding.saveNewPasswordButton.setEnabled(true);
binding.saveNewPasswordButton.setText("Guardar Palavra-passe");
String errorMsg = task.getException() != null ? task.getException().getMessage() : "Erro desconhecido";
Toast.makeText(this, "Erro: " + errorMsg, Toast.LENGTH_LONG).show();
}
});
}
}

View File

@@ -26,7 +26,7 @@ public class HomeFragment extends Fragment {
ViewGroup container, Bundle savedInstanceState) {
binding = FragmentHomeBinding.inflate(inflater, container, false);
// --- Greeting ---
// --- Greeting & Profile Picture ---
com.google.firebase.auth.FirebaseAuth auth = com.google.firebase.auth.FirebaseAuth.getInstance();
if (auth.getCurrentUser() != null) {
String userId = auth.getCurrentUser().getUid();
@@ -42,6 +42,16 @@ public class HomeFragment extends Fragment {
} else {
binding.textGreeting.setText("Olá, Utilizador!");
}
// Load Profile Picture
String profilePictureUri = documentSnapshot.getString("profilePictureUri");
if (profilePictureUri != null && !profilePictureUri.isEmpty()) {
try {
binding.imageProfileHome.setImageURI(android.net.Uri.parse(profilePictureUri));
} catch (Exception e) {
android.util.Log.e("HomeFragment", "Error loading profile pic view: " + e.getMessage());
}
}
}
})
.addOnFailureListener(e -> {

View File

@@ -59,9 +59,9 @@ public class Sns24Fragment extends Fragment {
com.example.cuida.services.Gemini gemini = new com.example.cuida.services.Gemini();
String prompt = "Atua como um assistente de triagem médica. " +
"Analisa os seguintes sintomas de um paciente e dá uma resposta MUITO CURTA e direta (máximo 2 a 3 frases). " +
"Regra de Ouro: Se o paciente mencionar a palavra 'dor', deves avaliar a situação com muito cuidado, inclinando-te para a classificar como severa. " +
"Se os sintomas indicarem uma situação grave, emergência ou necessidade de observação urgente de acordo com as tuas instruções, a tua resposta DEVE conter obrigatoriamente a palavra [GRAVE]. " +
"Recomenda sempre qual o próximo passo (ex: urgências, SNS 24, consulta). " +
"Tem bom senso e calma na avaliação: não assumas automaticamente que os sintomas são severos sem analisar todo o contexto. Evita ser alarmista desnecessariamente. " +
"Apenas se os sintomas indicarem uma situação de verdadeira emergência ou necessidade indiscutível de observação médica urgente, a tua resposta DEVE conter obrigatoriamente a palavra [GRAVE]. " +
"Recomenda sempre qual o próximo passo adequado (ex: repouso, farmácia, médico, SNS 24, ou urgências). " +
"Sintomas: " + symptoms;
gemini.fazerPergunta(prompt, new com.example.cuida.services.Gemini.GeminiCallback() {

View File

@@ -0,0 +1,68 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:padding="24dp"
android:background="@color/background_color">
<ImageView
android:layout_width="187dp"
android:layout_height="177dp"
android:layout_marginBottom="24dp"
android:scaleType="centerCrop"
android:src="@drawable/ic_logo" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Nova Palavra-passe"
android:textSize="24sp"
android:textStyle="bold"
android:textColor="@color/primary_color"
android:layout_marginBottom="16dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Insira e confirme a sua nova palavra-passe."
android:gravity="center"
android:textSize="16sp"
android:layout_marginBottom="32dp"/>
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/new_password_edit_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Nova palavra-passe"
android:inputType="textPassword" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="24dp">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/confirm_new_password_edit_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Confirmar palavra-passe"
android:inputType="textPassword" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.button.MaterialButton
android:id="@+id/save_new_password_button"
android:layout_width="match_parent"
android:layout_height="56dp"
android:text="Guardar Palavra-passe"
android:textSize="16sp"
android:layout_marginBottom="16dp"/>
</LinearLayout>

View File

@@ -5,16 +5,28 @@
android:layout_height="match_parent"
android:padding="16dp">
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/image_profile_home"
android:layout_width="48dp"
android:layout_height="48dp"
android:src="@drawable/ic_placeholder"
android:scaleType="centerCrop"
app:shapeAppearanceOverlay="@style/ShapeAppearanceOverlay.App.CornerSize50Percent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"/>
<TextView
android:id="@+id/text_greeting"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:text="Olá, utilizador!"
android:textSize="24sp"
android:textStyle="bold"
android:textColor="@color/primary_color"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"/>
app:layout_constraintTop_toTopOf="@id/image_profile_home"
app:layout_constraintBottom_toBottomOf="@id/image_profile_home"
app:layout_constraintStart_toEndOf="@id/image_profile_home"/>
<com.google.android.material.card.MaterialCardView
android:id="@+id/card_next_medication"
@@ -26,7 +38,7 @@
android:foreground="?android:attr/selectableItemBackground"
app:cardCornerRadius="16dp"
app:cardElevation="4dp"
app:layout_constraintTop_toBottomOf="@id/text_greeting">
app:layout_constraintTop_toBottomOf="@id/image_profile_home">
<LinearLayout
android:layout_width="match_parent"