ja acabei a app acho?
This commit is contained in:
@@ -9,9 +9,7 @@ import androidx.navigation.fragment.NavHostFragment;
|
||||
import androidx.navigation.ui.AppBarConfiguration;
|
||||
import androidx.navigation.ui.NavigationUI;
|
||||
import com.example.cuida.databinding.ActivityMainBinding;
|
||||
import com.google.android.material.bottomnavigation.BottomNavigationView;
|
||||
import com.example.cuida.ui.auth.LoginActivity;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Build;
|
||||
@@ -53,21 +51,11 @@ public class MainActivity extends AppCompatActivity {
|
||||
binding = ActivityMainBinding.inflate(getLayoutInflater());
|
||||
setContentView(binding.getRoot());
|
||||
|
||||
BottomNavigationView navView = binding.navView;
|
||||
|
||||
// Find Navigation Host Fragment and setup Bottom Navigation
|
||||
NavHostFragment navHostFragment = (NavHostFragment) getSupportFragmentManager()
|
||||
.findFragmentById(R.id.nav_host_fragment);
|
||||
|
||||
if (navHostFragment != null) {
|
||||
NavController navController = navHostFragment.getNavController();
|
||||
// Passing each menu ID as a set of Ids because each
|
||||
// menu should be considered as top level destinations.
|
||||
AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder(
|
||||
R.id.navigation_home, R.id.navigation_appointments, R.id.navigation_medication,
|
||||
R.id.navigation_sns24, R.id.navigation_profile)
|
||||
.build();
|
||||
// NavigationUI.setupActionBarWithNavController(this, navController,
|
||||
// appBarConfiguration);
|
||||
NavigationUI.setupWithNavController(binding.navView, navController);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
package com.example.cuida.config;
|
||||
|
||||
public class SupabaseConfig {
|
||||
public static final String URL = "https://iyngjivmpkbsxcetjcey.supabase.co";
|
||||
public static final String AUTH_URL = "sb_publishable_fngoScKM-mFFYGL_VpdIQw_amS_MyYy";
|
||||
public static final String API_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Iml5bmdqaXZtcGtic3hjZXRqY2V5Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3Njk2ODA5MTYsImV4cCI6MjA4NTI1NjkxNn0.zZtwcjNQmaABgJMlqteqH2mrJKcMwQR-OgpfR0h3WYA";
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
package com.example.cuida.data;
|
||||
|
||||
import android.content.Context;
|
||||
import androidx.room.Database;
|
||||
import androidx.room.Room;
|
||||
import androidx.room.RoomDatabase;
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase;
|
||||
import androidx.annotation.NonNull;
|
||||
import com.example.cuida.data.dao.UserDao;
|
||||
import com.example.cuida.data.dao.AppointmentDao;
|
||||
import com.example.cuida.data.dao.MedicationDao;
|
||||
import com.example.cuida.data.model.User;
|
||||
import com.example.cuida.data.model.Appointment;
|
||||
import com.example.cuida.data.model.Medication;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
@Database(entities = { User.class, Appointment.class, Medication.class }, version = 4, exportSchema = false)
|
||||
public abstract class AppDatabase extends RoomDatabase {
|
||||
|
||||
public abstract UserDao userDao();
|
||||
|
||||
public abstract AppointmentDao appointmentDao();
|
||||
|
||||
public abstract MedicationDao medicationDao();
|
||||
|
||||
private static volatile AppDatabase INSTANCE;
|
||||
private static final int NUMBER_OF_THREADS = 4;
|
||||
public static final ExecutorService databaseWriteExecutor = Executors.newFixedThreadPool(NUMBER_OF_THREADS);
|
||||
|
||||
public static AppDatabase getDatabase(final Context context) {
|
||||
if (INSTANCE == null) {
|
||||
synchronized (AppDatabase.class) {
|
||||
if (INSTANCE == null) {
|
||||
INSTANCE = Room.databaseBuilder(context.getApplicationContext(),
|
||||
AppDatabase.class, "cuida_database")
|
||||
.fallbackToDestructiveMigration()
|
||||
.addCallback(sRoomDatabaseCallback)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
}
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
private static RoomDatabase.Callback sRoomDatabaseCallback = new RoomDatabase.Callback() {
|
||||
@Override
|
||||
public void onCreate(@NonNull SupportSQLiteDatabase db) {
|
||||
super.onCreate(db);
|
||||
databaseWriteExecutor.execute(() -> {
|
||||
// Populate the database in the background.
|
||||
|
||||
MedicationDao medDao = INSTANCE.medicationDao();
|
||||
medDao.insert(new Medication("Paracetamol", "08:00", "1 comp", "Tomar com água"));
|
||||
medDao.insert(new Medication("Ibuprofeno", "14:00", "1 comp", "Após refeição"));
|
||||
medDao.insert(new Medication("Vitamina C", "20:00", "1 comp", "Antes de dormir"));
|
||||
|
||||
AppointmentDao apptDao = INSTANCE.appointmentDao();
|
||||
apptDao.insert(new Appointment("Medicina Geral", "25/01/2026", "10:00", "Check-up anual", false));
|
||||
apptDao.insert(new Appointment("Cardiologia", "02/02/2026", "15:30", "Dor no peito", false));
|
||||
apptDao.insert(new Appointment("Oftalmologia", "10/01/2025", "09:00", "Renovação óculos", true));
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package com.example.cuida.data.dao;
|
||||
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.room.Dao;
|
||||
import androidx.room.Insert;
|
||||
import androidx.room.Query;
|
||||
import com.example.cuida.data.model.Appointment;
|
||||
import java.util.List;
|
||||
|
||||
@Dao
|
||||
public interface AppointmentDao {
|
||||
@Insert
|
||||
void insert(Appointment appointment);
|
||||
|
||||
@Query("SELECT * FROM appointments WHERE isPast = 0 ORDER BY date ASC, time ASC")
|
||||
LiveData<List<Appointment>> getFutureAppointments();
|
||||
|
||||
@Query("SELECT * FROM appointments WHERE isPast = 1 ORDER BY date DESC, time DESC")
|
||||
LiveData<List<Appointment>> getPastAppointments();
|
||||
|
||||
@Query("SELECT time FROM appointments WHERE date = :date")
|
||||
List<String> getBookedTimesForDate(String date);
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package com.example.cuida.data.dao;
|
||||
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.room.Dao;
|
||||
import androidx.room.Insert;
|
||||
import androidx.room.Query;
|
||||
import com.example.cuida.data.model.Medication;
|
||||
import java.util.List;
|
||||
|
||||
@Dao
|
||||
public interface MedicationDao {
|
||||
@Insert
|
||||
void insert(Medication medication);
|
||||
|
||||
@androidx.room.Update
|
||||
void update(Medication medication);
|
||||
|
||||
@Query("SELECT * FROM medications ORDER BY time ASC")
|
||||
LiveData<List<Medication>> getAllMedications();
|
||||
|
||||
@Query("SELECT * FROM medications ORDER BY time ASC LIMIT 1")
|
||||
LiveData<Medication> getNextMedication();
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
package com.example.cuida.data.dao;
|
||||
|
||||
import androidx.room.Dao;
|
||||
import androidx.room.Insert;
|
||||
import androidx.room.Query;
|
||||
import androidx.room.Update;
|
||||
import androidx.room.OnConflictStrategy;
|
||||
import com.example.cuida.data.model.User;
|
||||
|
||||
@Dao
|
||||
public interface UserDao {
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
void insert(User user);
|
||||
|
||||
@Update
|
||||
void update(User user);
|
||||
|
||||
@Query("SELECT * FROM users WHERE email = :email AND password = :password LIMIT 1")
|
||||
User login(String email, String password);
|
||||
|
||||
@Query("SELECT * FROM users WHERE email = :email LIMIT 1")
|
||||
User checkUser(String email);
|
||||
|
||||
@Query("delete from users")
|
||||
void deleteAll();
|
||||
}
|
||||
@@ -1,12 +1,11 @@
|
||||
package com.example.cuida.data.model;
|
||||
|
||||
import androidx.room.Entity;
|
||||
import androidx.room.PrimaryKey;
|
||||
import com.google.firebase.firestore.DocumentId;
|
||||
|
||||
@Entity(tableName = "appointments")
|
||||
public class Appointment {
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
public int id;
|
||||
|
||||
@DocumentId
|
||||
public String id;
|
||||
|
||||
public String type; // e.g. "Medicina Geral", "Cardiologia"
|
||||
public String date; // dd/MM/yyyy
|
||||
@@ -14,6 +13,10 @@ public class Appointment {
|
||||
public String reason;
|
||||
public boolean isPast;
|
||||
|
||||
// Required empty constructor for Firestore deserialization
|
||||
public Appointment() {
|
||||
}
|
||||
|
||||
public Appointment(String type, String date, String time, String reason, boolean isPast) {
|
||||
this.type = type;
|
||||
this.date = date;
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
package com.example.cuida.data.model;
|
||||
|
||||
import androidx.room.Entity;
|
||||
import androidx.room.PrimaryKey;
|
||||
import com.google.firebase.firestore.DocumentId;
|
||||
|
||||
@Entity(tableName = "medications")
|
||||
public class Medication {
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
public int id;
|
||||
|
||||
@DocumentId
|
||||
public String id;
|
||||
|
||||
public String name;
|
||||
public String time; // HH:mm
|
||||
@@ -14,6 +13,10 @@ public class Medication {
|
||||
public String notes;
|
||||
public boolean isTaken;
|
||||
|
||||
// Required empty constructor for Firestore deserialization
|
||||
public Medication() {
|
||||
}
|
||||
|
||||
public Medication(String name, String time, String dosage, String notes) {
|
||||
this.name = name;
|
||||
this.time = time;
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
package com.example.cuida.data.model;
|
||||
|
||||
import androidx.room.Entity;
|
||||
import androidx.room.PrimaryKey;
|
||||
import com.google.firebase.firestore.DocumentId;
|
||||
|
||||
@Entity(tableName = "users")
|
||||
public class User {
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
public int uid;
|
||||
|
||||
@DocumentId
|
||||
public String id;
|
||||
|
||||
public String name;
|
||||
public String email;
|
||||
@@ -15,6 +14,10 @@ public class User {
|
||||
public String utenteNumber;
|
||||
public String profilePictureUri;
|
||||
|
||||
// Required empty constructor for Firestore deserialization
|
||||
public User() {
|
||||
}
|
||||
|
||||
public User(String name, String email, String password, int age, String utenteNumber) {
|
||||
this.name = name;
|
||||
this.email = email;
|
||||
|
||||
@@ -12,7 +12,6 @@ import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
public class Gemini {
|
||||
|
||||
private final GenerativeModelFutures modelo;
|
||||
|
||||
public Gemini() {
|
||||
|
||||
@@ -1,30 +1,79 @@
|
||||
package com.example.cuida.ui.appointments;
|
||||
|
||||
import android.app.Application;
|
||||
import android.util.Log;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.lifecycle.AndroidViewModel;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import com.example.cuida.data.AppDatabase;
|
||||
import com.example.cuida.data.dao.AppointmentDao;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
|
||||
import com.example.cuida.data.model.Appointment;
|
||||
import com.google.firebase.auth.FirebaseAuth;
|
||||
import com.google.firebase.firestore.FirebaseFirestore;
|
||||
import com.google.firebase.firestore.Query;
|
||||
import com.google.firebase.firestore.QueryDocumentSnapshot;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
public class AppointmentsViewModel extends AndroidViewModel {
|
||||
|
||||
private final AppointmentDao appointmentDao;
|
||||
private final LiveData<List<Appointment>> futureAppointments;
|
||||
private final LiveData<List<Appointment>> pastAppointments;
|
||||
private final ExecutorService executorService;
|
||||
private final MutableLiveData<List<Appointment>> futureAppointments = new MutableLiveData<>(new ArrayList<>());
|
||||
private final MutableLiveData<List<Appointment>> pastAppointments = new MutableLiveData<>(new ArrayList<>());
|
||||
private final FirebaseFirestore db;
|
||||
private final FirebaseAuth auth;
|
||||
|
||||
public AppointmentsViewModel(@NonNull Application application) {
|
||||
super(application);
|
||||
AppDatabase db = AppDatabase.getDatabase(application);
|
||||
appointmentDao = db.appointmentDao();
|
||||
futureAppointments = appointmentDao.getFutureAppointments();
|
||||
pastAppointments = appointmentDao.getPastAppointments();
|
||||
executorService = Executors.newSingleThreadExecutor();
|
||||
db = FirebaseFirestore.getInstance();
|
||||
auth = FirebaseAuth.getInstance();
|
||||
fetchAppointments();
|
||||
}
|
||||
|
||||
private void fetchAppointments() {
|
||||
if (auth.getCurrentUser() == null)
|
||||
return;
|
||||
String userId = auth.getCurrentUser().getUid();
|
||||
|
||||
// 1. Fetch Future Appointments
|
||||
db.collection("users").document(userId).collection("appointments")
|
||||
.whereEqualTo("isPast", false)
|
||||
.orderBy("date", Query.Direction.ASCENDING)
|
||||
.orderBy("time", Query.Direction.ASCENDING)
|
||||
.addSnapshotListener((value, error) -> {
|
||||
if (error != null) {
|
||||
Log.e("AppointmentsVM", "Listen failed for future.", error);
|
||||
return;
|
||||
}
|
||||
|
||||
List<Appointment> apps = new ArrayList<>();
|
||||
if (value != null) {
|
||||
for (QueryDocumentSnapshot doc : value) {
|
||||
apps.add(doc.toObject(Appointment.class));
|
||||
}
|
||||
}
|
||||
futureAppointments.setValue(apps);
|
||||
});
|
||||
|
||||
// 2. Fetch Past Appointments
|
||||
db.collection("users").document(userId).collection("appointments")
|
||||
.whereEqualTo("isPast", true)
|
||||
.orderBy("date", Query.Direction.DESCENDING)
|
||||
.orderBy("time", Query.Direction.DESCENDING)
|
||||
.addSnapshotListener((value, error) -> {
|
||||
if (error != null) {
|
||||
Log.e("AppointmentsVM", "Listen failed for past.", error);
|
||||
return;
|
||||
}
|
||||
|
||||
List<Appointment> apps = new ArrayList<>();
|
||||
if (value != null) {
|
||||
for (QueryDocumentSnapshot doc : value) {
|
||||
apps.add(doc.toObject(Appointment.class));
|
||||
}
|
||||
}
|
||||
pastAppointments.setValue(apps);
|
||||
});
|
||||
}
|
||||
|
||||
public LiveData<List<Appointment>> getFutureAppointments() {
|
||||
@@ -36,6 +85,13 @@ public class AppointmentsViewModel extends AndroidViewModel {
|
||||
}
|
||||
|
||||
public void insert(Appointment appointment) {
|
||||
executorService.execute(() -> appointmentDao.insert(appointment));
|
||||
if (auth.getCurrentUser() == null)
|
||||
return;
|
||||
String userId = auth.getCurrentUser().getUid();
|
||||
|
||||
db.collection("users").document(userId).collection("appointments")
|
||||
.add(appointment)
|
||||
.addOnSuccessListener(documentReference -> Log.d("AppointmentsVM", "Appointment added"))
|
||||
.addOnFailureListener(e -> Log.w("AppointmentsVM", "Error adding appointment", e));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,8 +6,6 @@ import android.os.Bundle;
|
||||
import android.widget.Toast;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import com.example.cuida.MainActivity;
|
||||
import com.example.cuida.data.AppDatabase;
|
||||
import com.example.cuida.data.dao.UserDao;
|
||||
import com.example.cuida.data.model.User;
|
||||
import com.example.cuida.databinding.ActivityLoginBinding;
|
||||
import com.example.cuida.R;
|
||||
@@ -65,16 +63,7 @@ public class LoginActivity extends AppCompatActivity {
|
||||
prefs.edit().putString("user_email", adminEmail).apply();
|
||||
prefs.edit().putString("user_name", "Administrador").apply();
|
||||
|
||||
// Ensure admin exists in DB
|
||||
UserDao userDao = AppDatabase.getDatabase(this).userDao();
|
||||
AppDatabase.databaseWriteExecutor.execute(() -> {
|
||||
if (userDao.checkUser(adminEmail) == null) {
|
||||
User adminUser = new User("Administrador", adminEmail, "123", 99, "000000000");
|
||||
// Set empty profile picture URI if needed to avoid null issues later, though
|
||||
// it's optional
|
||||
userDao.insert(adminUser);
|
||||
}
|
||||
});
|
||||
// Remove local Room admin creation since Room is gone
|
||||
|
||||
Toast.makeText(this, "Login de Administrador", Toast.LENGTH_SHORT).show();
|
||||
startActivity(new Intent(this, MainActivity.class));
|
||||
|
||||
@@ -4,18 +4,9 @@ import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.widget.Toast;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import com.example.cuida.data.AppDatabase;
|
||||
import com.example.cuida.data.dao.UserDao;
|
||||
import com.example.cuida.data.model.User;
|
||||
import com.example.cuida.databinding.ActivityRegisterBinding;
|
||||
|
||||
import com.google.firebase.auth.FirebaseAuth;
|
||||
import com.google.firebase.auth.FirebaseUser;
|
||||
import com.google.firebase.firestore.FirebaseFirestore;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class RegisterActivity extends AppCompatActivity {
|
||||
|
||||
private ActivityRegisterBinding binding;
|
||||
@@ -50,28 +41,29 @@ public class RegisterActivity extends AppCompatActivity {
|
||||
binding.registerButton.setEnabled(false);
|
||||
binding.registerButton.setText("A registar...");
|
||||
|
||||
FirebaseAuth mAuth = FirebaseAuth.getInstance();
|
||||
FirebaseFirestore db = FirebaseFirestore.getInstance();
|
||||
com.google.firebase.auth.FirebaseAuth mAuth = com.google.firebase.auth.FirebaseAuth.getInstance();
|
||||
com.google.firebase.firestore.FirebaseFirestore db = com.google.firebase.firestore.FirebaseFirestore
|
||||
.getInstance();
|
||||
|
||||
mAuth.createUserWithEmailAndPassword(email, password)
|
||||
.addOnCompleteListener(this, task -> {
|
||||
if (task.isSuccessful()) {
|
||||
// Registration success, save additional info to Firestore
|
||||
FirebaseUser firebaseUser = mAuth.getCurrentUser();
|
||||
com.google.firebase.auth.FirebaseUser firebaseUser = mAuth.getCurrentUser();
|
||||
if (firebaseUser != null) {
|
||||
String userId = firebaseUser.getUid();
|
||||
|
||||
Map<String, Object> userMap = new HashMap<>();
|
||||
userMap.put("nome_completo", name);
|
||||
userMap.put("idade", ageStr);
|
||||
userMap.put("numero_utente", utenteStr);
|
||||
java.util.Map<String, Object> userMap = new java.util.HashMap<>();
|
||||
userMap.put("uid", userId);
|
||||
userMap.put("name", name);
|
||||
userMap.put("email", email);
|
||||
userMap.put("age", age);
|
||||
userMap.put("utenteNumber", utenteStr);
|
||||
userMap.put("profilePictureUri", ""); // Init empty
|
||||
|
||||
db.collection("utilizadores").document(userId)
|
||||
db.collection("users").document(userId)
|
||||
.set(userMap)
|
||||
.addOnSuccessListener(aVoid -> {
|
||||
// Optional: Also save to local Room DB for offline cache if desired,
|
||||
// but for now we focus on Firebase as requested.
|
||||
|
||||
Toast.makeText(RegisterActivity.this, "Conta criada com sucesso!",
|
||||
Toast.LENGTH_SHORT).show();
|
||||
|
||||
@@ -1,25 +1,63 @@
|
||||
package com.example.cuida.ui.medication;
|
||||
|
||||
import android.app.Application;
|
||||
import android.util.Log;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.lifecycle.AndroidViewModel;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import com.example.cuida.data.AppDatabase;
|
||||
import com.example.cuida.data.dao.MedicationDao;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
|
||||
import com.example.cuida.data.model.Medication;
|
||||
import com.google.firebase.auth.FirebaseAuth;
|
||||
import com.google.firebase.firestore.FirebaseFirestore;
|
||||
import com.google.firebase.firestore.Query;
|
||||
import com.google.firebase.firestore.QueryDocumentSnapshot;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class MedicationViewModel extends AndroidViewModel {
|
||||
|
||||
private final LiveData<List<Medication>> allMedications;
|
||||
private final LiveData<Medication> nextMedication;
|
||||
private final MutableLiveData<List<Medication>> allMedications = new MutableLiveData<>(new ArrayList<>());
|
||||
private final MutableLiveData<Medication> nextMedication = new MutableLiveData<>(null);
|
||||
private final FirebaseFirestore db;
|
||||
private final FirebaseAuth auth;
|
||||
|
||||
public MedicationViewModel(@NonNull Application application) {
|
||||
super(application);
|
||||
AppDatabase db = AppDatabase.getDatabase(application);
|
||||
MedicationDao medicationDao = db.medicationDao();
|
||||
allMedications = medicationDao.getAllMedications();
|
||||
nextMedication = medicationDao.getNextMedication();
|
||||
db = FirebaseFirestore.getInstance();
|
||||
auth = FirebaseAuth.getInstance();
|
||||
fetchMedications();
|
||||
}
|
||||
|
||||
private void fetchMedications() {
|
||||
if (auth.getCurrentUser() == null)
|
||||
return;
|
||||
String userId = auth.getCurrentUser().getUid();
|
||||
|
||||
db.collection("users").document(userId).collection("medications")
|
||||
.orderBy("time", Query.Direction.ASCENDING)
|
||||
.addSnapshotListener((value, error) -> {
|
||||
if (error != null) {
|
||||
Log.e("MedicationViewModel", "Listen failed.", error);
|
||||
return;
|
||||
}
|
||||
|
||||
List<Medication> meds = new ArrayList<>();
|
||||
if (value != null) {
|
||||
for (QueryDocumentSnapshot doc : value) {
|
||||
Medication med = doc.toObject(Medication.class);
|
||||
meds.add(med);
|
||||
}
|
||||
}
|
||||
allMedications.setValue(meds);
|
||||
|
||||
if (!meds.isEmpty()) {
|
||||
nextMedication.setValue(meds.get(0));
|
||||
} else {
|
||||
nextMedication.setValue(null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public LiveData<List<Medication>> getAllMedications() {
|
||||
@@ -31,14 +69,25 @@ public class MedicationViewModel extends AndroidViewModel {
|
||||
}
|
||||
|
||||
public void insert(Medication medication) {
|
||||
AppDatabase.databaseWriteExecutor.execute(() -> {
|
||||
AppDatabase.getDatabase(getApplication()).medicationDao().insert(medication);
|
||||
});
|
||||
if (auth.getCurrentUser() == null)
|
||||
return;
|
||||
String userId = auth.getCurrentUser().getUid();
|
||||
|
||||
db.collection("users").document(userId).collection("medications")
|
||||
.add(medication)
|
||||
.addOnSuccessListener(documentReference -> Log.d("MedicationViewModel", "Medication added"))
|
||||
.addOnFailureListener(e -> Log.w("MedicationViewModel", "Error adding medication", e));
|
||||
}
|
||||
|
||||
public void update(Medication medication) {
|
||||
AppDatabase.databaseWriteExecutor.execute(() -> {
|
||||
AppDatabase.getDatabase(getApplication()).medicationDao().update(medication);
|
||||
});
|
||||
if (auth.getCurrentUser() == null || medication.id == null)
|
||||
return;
|
||||
String userId = auth.getCurrentUser().getUid();
|
||||
|
||||
db.collection("users").document(userId).collection("medications")
|
||||
.document(medication.id)
|
||||
.set(medication)
|
||||
.addOnSuccessListener(aVoid -> Log.d("MedicationViewModel", "Medication updated"))
|
||||
.addOnFailureListener(e -> Log.w("MedicationViewModel", "Error updating medication", e));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,39 +5,42 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.EditText;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import com.example.cuida.data.AppDatabase;
|
||||
import com.example.cuida.data.dao.UserDao;
|
||||
import com.example.cuida.data.model.User;
|
||||
|
||||
import com.example.cuida.R;
|
||||
import com.example.cuida.data.model.User;
|
||||
import com.example.cuida.databinding.FragmentProfileBinding;
|
||||
import com.example.cuida.ui.auth.LoginActivity;
|
||||
import com.google.firebase.auth.FirebaseAuth;
|
||||
import com.google.firebase.firestore.FirebaseFirestore;
|
||||
|
||||
public class ProfileFragment extends Fragment {
|
||||
|
||||
private FragmentProfileBinding binding;
|
||||
private User currentUser;
|
||||
private UserDao userDao;
|
||||
private FirebaseFirestore db;
|
||||
private FirebaseAuth auth;
|
||||
|
||||
public View onCreateView(@NonNull LayoutInflater inflater,
|
||||
ViewGroup container, Bundle savedInstanceState) {
|
||||
binding = FragmentProfileBinding.inflate(inflater, container, false);
|
||||
|
||||
userDao = AppDatabase.getDatabase(requireContext()).userDao();
|
||||
db = FirebaseFirestore.getInstance();
|
||||
auth = FirebaseAuth.getInstance();
|
||||
loadUserData();
|
||||
|
||||
binding.buttonEditProfile.setOnClickListener(v -> showEditDialog());
|
||||
|
||||
binding.buttonLogout.setOnClickListener(v -> {
|
||||
auth.signOut();
|
||||
getContext().getSharedPreferences("prefs", Context.MODE_PRIVATE).edit().clear().apply();
|
||||
Intent intent = new Intent(getContext(), LoginActivity.class);
|
||||
startActivity(intent);
|
||||
@@ -48,30 +51,40 @@ public class ProfileFragment extends Fragment {
|
||||
}
|
||||
|
||||
private void loadUserData() {
|
||||
SharedPreferences prefs = requireContext().getSharedPreferences("prefs", Context.MODE_PRIVATE);
|
||||
String email = prefs.getString("user_email", "");
|
||||
if (auth.getCurrentUser() == null)
|
||||
return;
|
||||
String userId = auth.getCurrentUser().getUid();
|
||||
|
||||
AppDatabase.databaseWriteExecutor.execute(() -> {
|
||||
currentUser = userDao.checkUser(email);
|
||||
if (currentUser != null) {
|
||||
getActivity().runOnUiThread(() -> {
|
||||
binding.profileName.setText(currentUser.name);
|
||||
binding.profileEmail.setText(currentUser.email);
|
||||
binding.profileAge.setText(String.valueOf(currentUser.age));
|
||||
binding.profileUtente.setText(currentUser.utenteNumber != null ? currentUser.utenteNumber : "N/A");
|
||||
if (currentUser.profilePictureUri != null) {
|
||||
android.widget.ImageView profileImage = binding.getRoot().findViewById(R.id.profile_image);
|
||||
if (profileImage != null) {
|
||||
try {
|
||||
profileImage.setImageURI(android.net.Uri.parse(currentUser.profilePictureUri));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
db.collection("users").document(userId).get()
|
||||
.addOnSuccessListener(documentSnapshot -> {
|
||||
if (documentSnapshot.exists()) {
|
||||
currentUser = documentSnapshot.toObject(User.class);
|
||||
if (currentUser != null && isAdded()) {
|
||||
binding.profileName.setText(currentUser.name);
|
||||
binding.profileEmail.setText(currentUser.email);
|
||||
binding.profileAge.setText(String.valueOf(currentUser.age));
|
||||
binding.profileUtente
|
||||
.setText(currentUser.utenteNumber != null ? currentUser.utenteNumber : "N/A");
|
||||
|
||||
if (currentUser.profilePictureUri != null && !currentUser.profilePictureUri.isEmpty()) {
|
||||
android.widget.ImageView profileImage = binding.getRoot()
|
||||
.findViewById(R.id.profile_image);
|
||||
if (profileImage != null) {
|
||||
try {
|
||||
profileImage.setImageURI(android.net.Uri.parse(currentUser.profilePictureUri));
|
||||
} catch (Exception e) {
|
||||
Log.e("ProfileFragment", "Error loading profile pic view: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.addOnFailureListener(e -> {
|
||||
if (isAdded()) {
|
||||
Toast.makeText(getContext(), "Failed to load profile data", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private android.net.Uri tempProfileUri;
|
||||
@@ -99,23 +112,18 @@ public class ProfileFragment extends Fragment {
|
||||
return;
|
||||
}
|
||||
|
||||
// Reset temp uri
|
||||
tempProfileUri = null;
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
|
||||
|
||||
// Inflate custom layout
|
||||
LayoutInflater inflater = requireActivity().getLayoutInflater();
|
||||
View dialogView = inflater.inflate(R.layout.dialog_edit_profile, null);
|
||||
builder.setView(dialogView);
|
||||
|
||||
AlertDialog dialog = builder.create();
|
||||
|
||||
// Bind Views
|
||||
EditText editName = dialogView.findViewById(R.id.edit_name);
|
||||
EditText editAge = dialogView.findViewById(R.id.edit_age);
|
||||
EditText editUtente = dialogView.findViewById(R.id.edit_utente);
|
||||
|
||||
EditText editEmail = dialogView.findViewById(R.id.edit_email);
|
||||
dialogImageView = dialogView.findViewById(R.id.edit_profile_image);
|
||||
View btnChangePhoto = dialogView.findViewById(R.id.button_change_photo);
|
||||
@@ -123,13 +131,12 @@ public class ProfileFragment extends Fragment {
|
||||
View btnSave = dialogView.findViewById(R.id.button_save);
|
||||
View btnCancel = dialogView.findViewById(R.id.button_cancel);
|
||||
|
||||
// Pre-fill data
|
||||
editName.setText(currentUser.name);
|
||||
editAge.setText(String.valueOf(currentUser.age));
|
||||
editUtente.setText(currentUser.utenteNumber);
|
||||
editEmail.setText(currentUser.email);
|
||||
|
||||
if (currentUser.profilePictureUri != null) {
|
||||
if (currentUser.profilePictureUri != null && !currentUser.profilePictureUri.isEmpty()) {
|
||||
dialogImageView.setImageURI(android.net.Uri.parse(currentUser.profilePictureUri));
|
||||
}
|
||||
|
||||
@@ -157,31 +164,39 @@ public class ProfileFragment extends Fragment {
|
||||
currentUser.name = newName;
|
||||
currentUser.age = newAge;
|
||||
currentUser.utenteNumber = newUtente;
|
||||
currentUser.email = newEmail;
|
||||
// Password not updated here
|
||||
|
||||
if (tempProfileUri != null) {
|
||||
currentUser.profilePictureUri = tempProfileUri.toString();
|
||||
}
|
||||
|
||||
AppDatabase.databaseWriteExecutor.execute(() -> {
|
||||
userDao.insert(currentUser);
|
||||
// Warning: We update the email field in Firestore, but FirebaseAuth updateEmail
|
||||
// requires re-authentication usually.
|
||||
// Assuming simple data sync for now.
|
||||
currentUser.email = newEmail;
|
||||
|
||||
// Update SharedPreferences if email changed (key for login persistence)
|
||||
if (emailChanged) {
|
||||
getContext().getSharedPreferences("prefs", Context.MODE_PRIVATE)
|
||||
.edit()
|
||||
.putString("user_email", newEmail)
|
||||
.apply();
|
||||
}
|
||||
String userId = auth.getCurrentUser().getUid();
|
||||
db.collection("users").document(userId)
|
||||
.set(currentUser)
|
||||
.addOnSuccessListener(aVoid -> {
|
||||
if (emailChanged) {
|
||||
getContext().getSharedPreferences("prefs", Context.MODE_PRIVATE)
|
||||
.edit()
|
||||
.putString("user_email", newEmail)
|
||||
.apply();
|
||||
}
|
||||
|
||||
getActivity().runOnUiThread(() -> {
|
||||
// UI update
|
||||
loadUserData(); // Reload to show new image and data
|
||||
Toast.makeText(getContext(), "Dados atualizados com sucesso!", Toast.LENGTH_SHORT).show();
|
||||
dialog.dismiss();
|
||||
dialogImageView = null; // Clear reference
|
||||
});
|
||||
});
|
||||
if (isAdded()) {
|
||||
loadUserData(); // Reload to show new image and data
|
||||
Toast.makeText(getContext(), "Dados atualizados com sucesso!", Toast.LENGTH_SHORT).show();
|
||||
dialog.dismiss();
|
||||
dialogImageView = null;
|
||||
}
|
||||
})
|
||||
.addOnFailureListener(e -> {
|
||||
if (isAdded()) {
|
||||
Toast.makeText(getContext(), "Erro a guardar perfil.", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
btnCancel.setOnClickListener(v -> {
|
||||
@@ -213,13 +228,17 @@ public class ProfileFragment extends Fragment {
|
||||
return;
|
||||
}
|
||||
|
||||
currentUser.password = newPass;
|
||||
AppDatabase.databaseWriteExecutor.execute(() -> {
|
||||
userDao.insert(currentUser);
|
||||
});
|
||||
|
||||
Toast.makeText(getContext(), "Palavra-passe alterada!", Toast.LENGTH_SHORT).show();
|
||||
dialog.dismiss();
|
||||
if (auth.getCurrentUser() != null) {
|
||||
auth.getCurrentUser().updatePassword(newPass).addOnCompleteListener(task -> {
|
||||
if (task.isSuccessful()) {
|
||||
Toast.makeText(getContext(), "Palavra-passe alterada!", Toast.LENGTH_SHORT).show();
|
||||
dialog.dismiss();
|
||||
} else {
|
||||
Toast.makeText(getContext(), "Erro a alterar: " + task.getException().getMessage(),
|
||||
Toast.LENGTH_LONG).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
btnCancel.setOnClickListener(v -> dialog.dismiss());
|
||||
|
||||
@@ -1,22 +1,26 @@
|
||||
package com.example.cuida.ui.schedule;
|
||||
|
||||
import android.app.Application;
|
||||
import android.util.Log;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.lifecycle.AndroidViewModel;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
import com.example.cuida.data.AppDatabase;
|
||||
import com.example.cuida.data.dao.AppointmentDao;
|
||||
|
||||
import com.example.cuida.data.model.Appointment;
|
||||
import com.example.cuida.utils.AlarmScheduler;
|
||||
import com.google.firebase.auth.FirebaseAuth;
|
||||
import com.google.firebase.firestore.FirebaseFirestore;
|
||||
import com.google.firebase.firestore.QueryDocumentSnapshot;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
public class ScheduleViewModel extends AndroidViewModel {
|
||||
|
||||
private final AppointmentDao appointmentDao;
|
||||
private final ExecutorService executorService;
|
||||
private final FirebaseFirestore db;
|
||||
private final FirebaseAuth auth;
|
||||
|
||||
private final MutableLiveData<String> selectedDate = new MutableLiveData<>();
|
||||
private final MutableLiveData<String> selectedTime = new MutableLiveData<>();
|
||||
@@ -25,14 +29,11 @@ public class ScheduleViewModel extends AndroidViewModel {
|
||||
|
||||
public ScheduleViewModel(@NonNull Application application) {
|
||||
super(application);
|
||||
AppDatabase db = AppDatabase.getDatabase(application);
|
||||
appointmentDao = db.appointmentDao();
|
||||
executorService = Executors.newSingleThreadExecutor();
|
||||
// Initial empty state or default date
|
||||
db = FirebaseFirestore.getInstance();
|
||||
auth = FirebaseAuth.getInstance();
|
||||
}
|
||||
|
||||
public void setDate(int year, int month, int dayOfMonth) {
|
||||
// Format to dd/MM/yyyy
|
||||
String date = String.format("%02d/%02d/%04d", dayOfMonth, month + 1, year);
|
||||
selectedDate.setValue(date);
|
||||
loadTimeSlots(date);
|
||||
@@ -44,8 +45,6 @@ public class ScheduleViewModel extends AndroidViewModel {
|
||||
|
||||
public void setTime(String time) {
|
||||
selectedTime.setValue(time);
|
||||
|
||||
// Update selection state in the list
|
||||
List<TimeSlot> currentSlots = timeSlots.getValue();
|
||||
if (currentSlots != null) {
|
||||
for (TimeSlot slot : currentSlots) {
|
||||
@@ -68,11 +67,30 @@ public class ScheduleViewModel extends AndroidViewModel {
|
||||
}
|
||||
|
||||
private void loadTimeSlots(String date) {
|
||||
executorService.execute(() -> {
|
||||
List<String> bookedTimes = appointmentDao.getBookedTimesForDate(date);
|
||||
List<TimeSlot> slots = generateTimeSlots(bookedTimes);
|
||||
timeSlots.postValue(slots);
|
||||
});
|
||||
if (auth.getCurrentUser() == null)
|
||||
return;
|
||||
String userId = auth.getCurrentUser().getUid();
|
||||
|
||||
db.collection("users").document(userId).collection("appointments")
|
||||
.whereEqualTo("date", date)
|
||||
.get()
|
||||
.addOnCompleteListener(task -> {
|
||||
if (task.isSuccessful()) {
|
||||
List<String> bookedTimes = new ArrayList<>();
|
||||
for (QueryDocumentSnapshot document : task.getResult()) {
|
||||
Appointment appt = document.toObject(Appointment.class);
|
||||
if (appt.time != null) {
|
||||
bookedTimes.add(appt.time);
|
||||
}
|
||||
}
|
||||
List<TimeSlot> slots = generateTimeSlots(bookedTimes);
|
||||
timeSlots.setValue(slots);
|
||||
} else {
|
||||
Log.e("ScheduleViewModel", "Error getting booked slots", task.getException());
|
||||
List<TimeSlot> slots = generateTimeSlots(new ArrayList<>());
|
||||
timeSlots.setValue(slots);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private List<TimeSlot> generateTimeSlots(List<String> bookedTimes) {
|
||||
@@ -89,8 +107,6 @@ public class ScheduleViewModel extends AndroidViewModel {
|
||||
|
||||
private void addSlot(List<TimeSlot> slots, String time, List<String> bookedTimes) {
|
||||
boolean isBooked = bookedTimes.contains(time);
|
||||
// If current selected time is now booked (e.g. concurrent), deselect it?
|
||||
// For simplicity, just check booked state.
|
||||
boolean isSelected = time.equals(selectedTime.getValue());
|
||||
slots.add(new TimeSlot(time, isBooked, isSelected));
|
||||
}
|
||||
@@ -99,42 +115,47 @@ public class ScheduleViewModel extends AndroidViewModel {
|
||||
String date = selectedDate.getValue();
|
||||
String time = selectedTime.getValue();
|
||||
|
||||
if (auth.getCurrentUser() == null)
|
||||
return;
|
||||
String userId = auth.getCurrentUser().getUid();
|
||||
|
||||
if (date != null && time != null) {
|
||||
Appointment appointment = new Appointment("Consulta Geral", date, time, reason, false);
|
||||
executorService.execute(() -> {
|
||||
appointmentDao.insert(appointment);
|
||||
|
||||
try {
|
||||
String[] dateParts = date.split("/");
|
||||
int day = Integer.parseInt(dateParts[0]);
|
||||
int month = Integer.parseInt(dateParts[1]) - 1; // 0-based
|
||||
int year = Integer.parseInt(dateParts[2]);
|
||||
db.collection("users").document(userId).collection("appointments")
|
||||
.add(appointment)
|
||||
.addOnSuccessListener(documentReference -> {
|
||||
try {
|
||||
String[] dateParts = date.split("/");
|
||||
int day = Integer.parseInt(dateParts[0]);
|
||||
int month = Integer.parseInt(dateParts[1]) - 1; // 0-based
|
||||
int year = Integer.parseInt(dateParts[2]);
|
||||
|
||||
String[] timeParts = time.split(":");
|
||||
int hour = Integer.parseInt(timeParts[0]);
|
||||
int minute = Integer.parseInt(timeParts[1]);
|
||||
String[] timeParts = time.split(":");
|
||||
int hour = Integer.parseInt(timeParts[0]);
|
||||
int minute = Integer.parseInt(timeParts[1]);
|
||||
|
||||
java.util.Calendar calendar = java.util.Calendar.getInstance();
|
||||
calendar.set(year, month, day, hour, minute, 0);
|
||||
// 1 hour before
|
||||
calendar.add(java.util.Calendar.HOUR_OF_DAY, -1);
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.set(year, month, day, hour, minute, 0);
|
||||
// 1 hour before
|
||||
calendar.add(Calendar.HOUR_OF_DAY, -1);
|
||||
|
||||
if (calendar.getTimeInMillis() > System.currentTimeMillis()) {
|
||||
String title = "Lembrete de Consulta";
|
||||
String msg = "A sua consulta é daqui a 1 hora (" + time + ").";
|
||||
com.example.cuida.utils.AlarmScheduler.scheduleAlarm(
|
||||
getApplication(),
|
||||
calendar.getTimeInMillis(),
|
||||
title,
|
||||
msg,
|
||||
(date + time).hashCode());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
saveSuccess.postValue(true);
|
||||
});
|
||||
if (calendar.getTimeInMillis() > System.currentTimeMillis()) {
|
||||
String title = "Lembrete de Consulta";
|
||||
String msg = "A sua consulta é daqui a 1 hora (" + time + ").";
|
||||
AlarmScheduler.scheduleAlarm(
|
||||
getApplication(),
|
||||
calendar.getTimeInMillis(),
|
||||
title,
|
||||
msg,
|
||||
(date + time).hashCode());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
saveSuccess.postValue(true);
|
||||
})
|
||||
.addOnFailureListener(e -> Log.e("ScheduleViewModel", "Failed to confirm appt", e));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,30 +12,18 @@ import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.google.ai.client.generativeai.GenerativeModel;
|
||||
import com.google.ai.client.generativeai.java.GenerativeModelFutures;
|
||||
import com.google.ai.client.generativeai.type.Content;
|
||||
import com.google.ai.client.generativeai.type.GenerateContentResponse;
|
||||
import com.google.common.util.concurrent.FutureCallback;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import com.example.cuida.databinding.FragmentSns24Binding;
|
||||
|
||||
public class Sns24Fragment extends Fragment {
|
||||
|
||||
private FragmentSns24Binding binding;
|
||||
private GenerativeModelFutures model;
|
||||
private static final String API_KEY = "AIzaSyBmLgn-SHaTDvAeDWsw2iTZRR9gahhOu7k";
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
|
||||
@Nullable Bundle savedInstanceState) {
|
||||
binding = FragmentSns24Binding.inflate(inflater, container, false);
|
||||
View view = inflater.inflate(com.example.cuida.R.layout.fragment_sns24, container, false);
|
||||
binding = FragmentSns24Binding.bind(view);
|
||||
return binding.getRoot();
|
||||
}
|
||||
|
||||
@@ -43,11 +31,6 @@ public class Sns24Fragment extends Fragment {
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
|
||||
// 1. Inicializar o Modelo Gemini
|
||||
// NOTA: Substitua "SUA_API_KEY" pela sua chave do Google AI Studio
|
||||
GenerativeModel gm = new GenerativeModel("gemini-2.5-flash", API_KEY);
|
||||
model = GenerativeModelFutures.from(gm);
|
||||
|
||||
// 2. Botão Ligar SNS 24
|
||||
binding.buttonCallSns.setOnClickListener(v -> {
|
||||
Intent intent = new Intent(Intent.ACTION_DIAL);
|
||||
@@ -70,56 +53,49 @@ public class Sns24Fragment extends Fragment {
|
||||
// Feedback visual de carregamento
|
||||
binding.buttonAiTriage.setEnabled(false);
|
||||
binding.textAiResult.setVisibility(View.VISIBLE);
|
||||
binding.textAiResult.setText("A analisar sintomas com IA...");
|
||||
binding.textAiResult.setText("A contactar a Inteligência Artificial...");
|
||||
binding.buttonFindHospital.setVisibility(View.GONE);
|
||||
|
||||
// Criar o prompt
|
||||
Content content = new Content.Builder()
|
||||
.addText("Atua como um assistente de triagem de saúde. O utilizador diz: \"" + symptoms + "\". " +
|
||||
"Se a situação exigir avaliação médica imediata ou urgência, começa a resposta com 'URGENTE: HOSPITAL'. "
|
||||
+
|
||||
"Caso contrário, dá apenas o conselho habitual. " +
|
||||
"Dá uma resposta curta (máximo 4 linhas). " +
|
||||
"Aviso: Isto não substitui aconselhamento médico.")
|
||||
.build();
|
||||
com.example.cuida.services.Gemini gemini = new com.example.cuida.services.Gemini();
|
||||
String prompt = "Atua como um assistente de triagem médica (em português europeu). " +
|
||||
"Analisa os seguintes sintomas de um paciente e dá uma resposta curta (1 ou 2 parágrafos no máximo) " +
|
||||
"avaliando a urgência e com uma recomendação clara (ir às urgências, ligar ao SNS 24 ou marcar consulta local). "
|
||||
+
|
||||
"Sintomas: " + symptoms;
|
||||
|
||||
// Executar chamada assíncrona (usando Guava Futures para Java)
|
||||
ListenableFuture<GenerateContentResponse> response = model.generateContent(content);
|
||||
|
||||
// Executor para rodar a resposta na UI Thread
|
||||
// Creating a new single thread executor for the background work if needed,
|
||||
// but the callback needs to run on main thread or handle UI updates on main
|
||||
// thread.
|
||||
// We use ContextCompat.getMainExecutor to be safe on API < 28 (minSdk is 24)
|
||||
|
||||
Futures.addCallback(response, new FutureCallback<GenerateContentResponse>() {
|
||||
gemini.fazerPergunta(prompt, new com.example.cuida.services.Gemini.GeminiCallback() {
|
||||
@Override
|
||||
public void onSuccess(GenerateContentResponse result) {
|
||||
if (getActivity() != null) {
|
||||
String text = result.getText();
|
||||
binding.textAiResult.setText(text);
|
||||
binding.buttonAiTriage.setEnabled(true);
|
||||
public void onSuccess(String result) {
|
||||
if (getActivity() != null && binding != null) {
|
||||
getActivity().runOnUiThread(() -> {
|
||||
binding.textAiResult.setText(result);
|
||||
binding.buttonAiTriage.setEnabled(true);
|
||||
|
||||
if (text != null && text.contains("URGENTE: HOSPITAL")) {
|
||||
binding.buttonFindHospital.setVisibility(View.VISIBLE);
|
||||
binding.buttonFindHospital.setOnClickListener(v -> {
|
||||
Uri gmmIntentUri = Uri.parse("geo:0,0?q=hospital");
|
||||
Intent mapIntent = new Intent(Intent.ACTION_VIEW, gmmIntentUri);
|
||||
mapIntent.setPackage("com.google.android.apps.maps");
|
||||
startActivity(mapIntent);
|
||||
});
|
||||
}
|
||||
String resultLower = result.toLowerCase();
|
||||
if (resultLower.contains("urgência") || resultLower.contains("hospital")
|
||||
|| resultLower.contains("112")) {
|
||||
binding.buttonFindHospital.setVisibility(View.VISIBLE);
|
||||
binding.buttonFindHospital.setOnClickListener(v -> {
|
||||
Uri gmmIntentUri = Uri.parse("geo:0,0?q=hospital");
|
||||
Intent mapIntent = new Intent(Intent.ACTION_VIEW, gmmIntentUri);
|
||||
mapIntent.setPackage("com.google.android.apps.maps");
|
||||
startActivity(mapIntent);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable t) {
|
||||
if (getActivity() != null) {
|
||||
binding.textAiResult.setText("Erro ao contactar a IA: " + t.getMessage());
|
||||
binding.buttonAiTriage.setEnabled(true);
|
||||
public void onError(Throwable t) {
|
||||
if (getActivity() != null && binding != null) {
|
||||
getActivity().runOnUiThread(() -> {
|
||||
binding.textAiResult.setText("Falha na comunicação com a IA: " + t.getMessage());
|
||||
binding.buttonAiTriage.setEnabled(true);
|
||||
});
|
||||
}
|
||||
}
|
||||
}, androidx.core.content.ContextCompat.getMainExecutor(requireContext()));
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user