ja meti o droplist nos medicamentos

This commit is contained in:
2026-04-15 12:33:39 +01:00
parent cbfb87d052
commit 069562ecf3
34 changed files with 1678 additions and 1704 deletions

View File

@@ -0,0 +1,92 @@
package com.example.cuida.ui.home;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import com.example.cuida.databinding.FragmentHomeBinding;
import com.example.cuida.ui.medication.MedicationViewModel;
import com.example.cuida.ui.appointments.AppointmentsViewModel;
import com.example.cuida.data.model.Appointment;
import java.util.Calendar;
import java.util.Locale;
public class HomeFragment extends Fragment {
private FragmentHomeBinding binding;
private MedicationViewModel medicationViewModel;
private AppointmentsViewModel appointmentsViewModel;
public View onCreateView(@NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
binding = FragmentHomeBinding.inflate(inflater, container, false);
// --- Greeting & Profile Picture ---
com.google.firebase.auth.FirebaseAuth auth = com.google.firebase.auth.FirebaseAuth.getInstance();
if (auth.getCurrentUser() != null) {
String userId = auth.getCurrentUser().getUid();
com.google.firebase.firestore.FirebaseFirestore.getInstance().collection("utilizadores").document(userId)
.get()
.addOnSuccessListener(documentSnapshot -> {
if (documentSnapshot.exists() && isAdded()) {
String name = documentSnapshot.getString("name");
if (name != null && !name.isEmpty()) {
// Extract first name
String firstName = name.split(" ")[0];
binding.textGreeting.setText("Olá, " + firstName + "!");
} 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 -> {
if (isAdded())
binding.textGreeting.setText("Olá, Utilizador!");
});
} else {
binding.textGreeting.setText("Olá, Utilizador!");
}
// --- Next Medication ---
medicationViewModel = new ViewModelProvider(this).get(MedicationViewModel.class);
medicationViewModel.getNextMedication().observe(getViewLifecycleOwner(), medication -> {
if (medication != null) {
binding.nextMedName.setText(medication.name + " (" + medication.dosage + ")");
binding.nextMedTime.setText("Hoje, " + medication.time);
} else {
binding.nextMedName.setText("Sem medicação");
binding.nextMedTime.setText("--:--");
}
});
// --- Book Appointment ---
appointmentsViewModel = new ViewModelProvider(this).get(AppointmentsViewModel.class);
binding.buttonBookAppointment.setOnClickListener(v -> {
androidx.navigation.Navigation.findNavController(v)
.navigate(com.example.cuida.R.id.action_home_to_schedule_appointment);
});
return binding.getRoot();
}
@Override
public void onDestroyView() {
super.onDestroyView();
binding = null;
}
}

View File

@@ -0,0 +1,85 @@
package com.example.cuida.ui.medication;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.example.cuida.R;
import com.example.cuida.data.model.Medication;
import java.util.ArrayList;
import java.util.List;
public class MedicationAdapter extends RecyclerView.Adapter<MedicationAdapter.MedicationViewHolder> {
private List<Medication> medicationList = new ArrayList<>();
private final OnItemClickListener listener;
public interface OnItemClickListener {
void onCheckClick(Medication medication);
void onItemClick(Medication medication);
}
public MedicationAdapter(OnItemClickListener listener) {
this.listener = listener;
}
public void setMedications(List<Medication> medications) {
this.medicationList = medications;
notifyDataSetChanged();
}
@NonNull
@Override
public MedicationViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_medication, parent, false);
return new MedicationViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull MedicationViewHolder holder, int position) {
Medication medication = medicationList.get(position);
holder.textName.setText(medication.name);
holder.textDosage.setText(medication.dosage);
holder.textTime.setText(medication.time);
holder.textNotes.setText(medication.notes);
// Remove listener temporarily to avoid triggering it during bind
holder.checkBoxTaken.setOnCheckedChangeListener(null);
holder.checkBoxTaken.setChecked(medication.isTaken);
holder.checkBoxTaken.setOnCheckedChangeListener((buttonView, isChecked) -> {
medication.isTaken = isChecked;
listener.onCheckClick(medication);
});
}
@Override
public int getItemCount() {
return medicationList.size();
}
public class MedicationViewHolder extends RecyclerView.ViewHolder {
TextView textName, textDosage, textTime, textNotes;
CheckBox checkBoxTaken;
public MedicationViewHolder(@NonNull View itemView) {
super(itemView);
textName = itemView.findViewById(R.id.text_med_name);
textDosage = itemView.findViewById(R.id.text_med_dosage);
textTime = itemView.findViewById(R.id.text_med_time);
textNotes = itemView.findViewById(R.id.text_med_notes);
checkBoxTaken = itemView.findViewById(R.id.checkbox_taken);
itemView.setOnClickListener(v -> {
int position = getAdapterPosition();
if (listener != null && position != RecyclerView.NO_POSITION) {
listener.onItemClick(medicationList.get(position));
}
});
}
}
}

View File

@@ -0,0 +1,368 @@
package com.example.cuida.ui.medication;
import android.app.Dialog;
import android.app.TimePickerDialog;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.textfield.TextInputEditText;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.DialogFragment;
import com.example.cuida.R;
import com.example.cuida.data.model.Medication;
import java.util.Calendar;
import java.util.Locale;
import java.util.ArrayList;
import java.util.List;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.ValueEventListener;
import android.text.Editable;
import android.text.TextWatcher;
import com.example.cuida.data.model.Comprimido;
import android.widget.AdapterView;
import android.widget.Toast;
import com.google.android.material.chip.Chip;
import com.google.android.material.chip.ChipGroup;
import com.google.android.material.button.MaterialButton;
import java.util.Collections;
public class MedicationDialog extends DialogFragment {
private TextInputEditText editName;
private RecyclerView recyclerResults;
private ComprimidoRecyclerAdapter recyclerAdapter;
private List<Comprimido> searchResults = new ArrayList<>();
private List<Comprimido> fullPillsList = new ArrayList<>();
private DatabaseReference medicationRef;
private EditText editNotes;
private android.widget.RadioButton radioOral, radioTopical, radioInhalatory;
private android.widget.RadioGroup radioGroupRoute;
private ChipGroup chipGroupTimes;
private List<String> selectedTimes = new ArrayList<>();
private Medication medicationToEdit;
private OnMedicationSaveListener listener;
private OnMedicationDeleteListener deleteListener;
public interface OnMedicationSaveListener {
void onSave(Medication medication);
}
public interface OnMedicationDeleteListener {
void onDelete(Medication medication);
}
public void setListener(OnMedicationSaveListener listener) {
this.listener = listener;
}
public void setDeleteListener(OnMedicationDeleteListener listener) {
this.deleteListener = listener;
}
public void setMedicationToEdit(Medication medication) {
this.medicationToEdit = medication;
}
@NonNull
@Override
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(requireContext());
LayoutInflater inflater = requireActivity().getLayoutInflater();
View view = inflater.inflate(R.layout.dialog_add_medication, null);
editName = view.findViewById(R.id.edit_med_name);
recyclerResults = view.findViewById(R.id.recycler_search_results);
editNotes = view.findViewById(R.id.edit_med_notes);
chipGroupTimes = view.findViewById(R.id.chip_group_times);
MaterialButton btnAddTime = view.findViewById(R.id.btn_add_time);
radioGroupRoute = view.findViewById(R.id.radio_group_route);
radioOral = view.findViewById(R.id.radio_oral);
radioTopical = view.findViewById(R.id.radio_topical);
radioInhalatory = view.findViewById(R.id.radio_inhalatory);
final android.content.Context currentContext = getContext();
if (currentContext != null) {
recyclerAdapter = new ComprimidoRecyclerAdapter(searchResults, selected -> {
editName.setText(selected.nome);
editName.setSelection(selected.nome.length());
// Adiciona a dosagem/informação ao campo de notas automaticamente
if (selected.dosagem != null && !selected.dosagem.isEmpty()) {
editNotes.setText(selected.dosagem);
}
recyclerResults.setVisibility(View.GONE);
searchResults.clear();
});
recyclerResults.setLayoutManager(new LinearLayoutManager(currentContext));
recyclerResults.setAdapter(recyclerAdapter);
String dbUrl = "https://cuidamais-7b904-default-rtdb.firebaseio.com/";
medicationRef = FirebaseDatabase.getInstance(dbUrl).getReference("medication");
// Carregar todos os medicamentos uma única vez para filtragem local rápida
fetchAllMedsOnce();
editName.addTextChangedListener(new TextWatcher() {
@Override public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
filterMedsLocally(s.toString().trim());
}
@Override public void afterTextChanged(Editable s) {}
});
}
radioGroupRoute = view.findViewById(R.id.radio_group_route);
radioOral = view.findViewById(R.id.radio_oral);
radioTopical = view.findViewById(R.id.radio_topical);
radioInhalatory = view.findViewById(R.id.radio_inhalatory);
// Set up TimePicker
btnAddTime.setOnClickListener(v -> showTimePicker());
if (medicationToEdit != null) {
editName.setText(medicationToEdit.name);
editNotes.setText(medicationToEdit.notes);
if (medicationToEdit.time != null && !medicationToEdit.time.isEmpty()) {
String[] times = medicationToEdit.time.split(",\\s*");
for (String t : times) {
if (!t.isEmpty()) selectedTimes.add(t);
}
refreshTimeChips();
}
String dosage = medicationToEdit.dosage;
if (dosage != null) {
if (dosage.contains("Oral"))
radioOral.setChecked(true);
else if (dosage.contains("Tópica"))
radioTopical.setChecked(true);
else if (dosage.contains("Inalatória"))
radioInhalatory.setChecked(true);
}
builder.setTitle("Editar Medicamento");
} else {
builder.setTitle("Adicionar Medicamento");
// Default time to current time
Calendar cal = Calendar.getInstance();
String defaultTime = String.format(Locale.getDefault(), "%02d:%02d", cal.get(Calendar.HOUR_OF_DAY), cal.get(Calendar.MINUTE));
selectedTimes.add(defaultTime);
refreshTimeChips();
}
builder.setView(view)
.setPositiveButton("Guardar", (dialog, id) -> {
String name = editName.getText().toString();
String notes = editNotes.getText().toString();
// Join times with comma
StringBuilder timeBuilder = new StringBuilder();
for (int i = 0; i < selectedTimes.size(); i++) {
timeBuilder.append(selectedTimes.get(i));
if (i < selectedTimes.size() - 1) timeBuilder.append(", ");
}
String time = timeBuilder.toString();
int selectedId = radioGroupRoute.getCheckedRadioButtonId();
String dosage = "Via não especificada";
if (selectedId == R.id.radio_oral) {
dosage = "Via Oral";
} else if (selectedId == R.id.radio_topical) {
dosage = "Via Tópica";
} else if (selectedId == R.id.radio_inhalatory) {
dosage = "Via Inalatória";
}
if (medicationToEdit != null) {
medicationToEdit.name = name;
medicationToEdit.dosage = dosage;
medicationToEdit.notes = notes;
medicationToEdit.time = time;
if (listener != null)
listener.onSave(medicationToEdit);
} else {
Medication newMed = new Medication(name, time, dosage, notes, null);
if (listener != null)
listener.onSave(newMed);
}
});
if (medicationToEdit != null) {
builder.setNeutralButton("Eliminar", (dialog, id) -> {
if (deleteListener != null) {
deleteListener.onDelete(medicationToEdit);
}
});
}
AlertDialog alertDialog = builder.create();
alertDialog.setOnShowListener(d -> {
android.widget.Button btnPos = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE);
if (btnPos != null) {
// Apply our custom outline drawable to "Guardar"
btnPos.setBackgroundResource(R.drawable.btn_outline_primary);
btnPos.setTextColor(androidx.core.content.ContextCompat.getColor(requireContext(), R.color.primary_color));
int paddingPx = (int) (16 * getResources().getDisplayMetrics().density);
btnPos.setPadding(paddingPx, 0, paddingPx, 0);
}
android.widget.Button btnNeu = alertDialog.getButton(AlertDialog.BUTTON_NEUTRAL);
if (btnNeu != null) {
btnNeu.setTextColor(androidx.core.content.ContextCompat.getColor(requireContext(), R.color.error_color));
btnNeu.setBackgroundResource(R.drawable.btn_outline_error);
int paddingPx = (int) (16 * getResources().getDisplayMetrics().density);
btnNeu.setPadding(paddingPx, 0, paddingPx, 0);
android.view.ViewGroup.LayoutParams lp = btnNeu.getLayoutParams();
if (lp instanceof android.view.ViewGroup.MarginLayoutParams) {
android.view.ViewGroup.MarginLayoutParams marginLp = (android.view.ViewGroup.MarginLayoutParams) lp;
int marginPx = (int) (8 * getResources().getDisplayMetrics().density);
marginLp.setMargins(marginLp.leftMargin, marginLp.topMargin, marginLp.rightMargin + marginPx, marginLp.bottomMargin);
btnNeu.setLayoutParams(marginLp);
}
}
});
return alertDialog;
}
private void showTimePicker() {
Calendar cal = Calendar.getInstance();
int hour = cal.get(Calendar.HOUR_OF_DAY);
int minute = cal.get(Calendar.MINUTE);
TimePickerDialog timePickerDialog = new TimePickerDialog(getContext(),
(view, hourOfDay, minute1) -> {
String time = String.format(Locale.getDefault(), "%02d:%02d", hourOfDay, minute1);
if (!selectedTimes.contains(time)) {
selectedTimes.add(time);
Collections.sort(selectedTimes);
refreshTimeChips();
}
},
hour, minute, true);
timePickerDialog.show();
}
private void refreshTimeChips() {
if (chipGroupTimes == null) return;
chipGroupTimes.removeAllViews();
for (String time : selectedTimes) {
Chip chip = new Chip(requireContext());
chip.setText(time);
chip.setCloseIconVisible(true);
chip.setOnCloseIconClickListener(v -> {
selectedTimes.remove(time);
refreshTimeChips();
});
chipGroupTimes.addView(chip);
}
}
private void fetchAllMedsOnce() {
String dbUrl = "https://cuidamais-7b904-default-rtdb.firebaseio.com/";
DatabaseReference rootRef = FirebaseDatabase.getInstance(dbUrl).getReference();
String[] nodes = {"medication", "medicamentos", "Medicamentos", "comprimidos"};
fullPillsList.clear();
// 1. Tentar nos nós específicos
for (String node : nodes) {
rootRef.child(node).addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot snapshot) {
if (snapshot.exists()) {
parseSnapshot(snapshot, "Nó: " + node);
}
}
@Override public void onCancelled(@NonNull DatabaseError error) {}
});
}
// 2. Tentar também na raiz (caso os medicamentos estejam diretamente no topo)
rootRef.limitToFirst(50).addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot snapshot) {
if (snapshot.exists()) {
parseSnapshot(snapshot, "Raiz");
}
}
@Override public void onCancelled(@NonNull DatabaseError error) {}
});
}
private void parseSnapshot(DataSnapshot snapshot, String source) {
int count = 0;
for (DataSnapshot child : snapshot.getChildren()) {
String name = child.child("nome").getValue(String.class);
if (name == null) name = child.child("name").getValue(String.class);
if (name == null && !(child.getValue() instanceof java.util.Map)) {
// Se o valor for a própria string (ex: "Paracetamol")
name = child.getValue() instanceof String ? (String) child.getValue() : null;
}
if (name == null) name = child.getKey();
String dosage = child.child("dosagem").getValue(String.class);
if (dosage == null) dosage = child.child("dosage").getValue(String.class);
if (dosage == null) dosage = "";
if (name != null && !name.isEmpty()) {
boolean exists = false;
for (Comprimido p : fullPillsList) {
if (name.equals(p.nome)) { exists = true; break; }
}
if (!exists) {
fullPillsList.add(new Comprimido(name, dosage));
count++;
}
}
}
if (count > 0 && getContext() != null) {
Log.d("FirebaseSearch", "Carregados " + count + " de " + source);
// Toast.makeText(getContext(), "Fonte: " + source + " (" + count + ")", Toast.LENGTH_SHORT).show();
}
}
private void filterMedsLocally(String query) {
searchResults.clear();
if (query.isEmpty()) {
recyclerResults.setVisibility(View.GONE);
recyclerAdapter.notifyDataSetChanged();
return;
}
String lowerQuery = query.toLowerCase();
for (Comprimido p : fullPillsList) {
if (p.nome != null && p.nome.toLowerCase().contains(lowerQuery)) {
searchResults.add(p);
}
}
recyclerAdapter.notifyDataSetChanged();
recyclerResults.setVisibility(searchResults.isEmpty() ? View.GONE : View.VISIBLE);
}
private void handleError(DatabaseError error) {
Log.e("FirebaseSearch", "Erro: " + error.getMessage());
if (getContext() != null) {
Toast.makeText(getContext(), "Erro no Firebase: " + error.getMessage(), Toast.LENGTH_LONG).show();
}
}
}

View File

@@ -0,0 +1,141 @@
package com.example.cuida.ui.medication;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager;
import com.example.cuida.data.model.Medication;
import com.example.cuida.databinding.FragmentMedicationBinding;
public class MedicationFragment extends Fragment {
private FragmentMedicationBinding binding;
private MedicationViewModel medicationViewModel;
public View onCreateView(@NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
medicationViewModel = new ViewModelProvider(this).get(MedicationViewModel.class);
binding = FragmentMedicationBinding.inflate(inflater, container, false);
MedicationAdapter adapter = new MedicationAdapter(new MedicationAdapter.OnItemClickListener() {
@Override
public void onCheckClick(Medication medication) {
medicationViewModel.update(medication);
}
@Override
public void onItemClick(Medication medication) {
showMedicationDialog(medication);
}
});
binding.recyclerMedication.setLayoutManager(new LinearLayoutManager(getContext()));
binding.recyclerMedication.setAdapter(adapter);
medicationViewModel.getAllMedications().observe(getViewLifecycleOwner(), medications -> {
adapter.setMedications(medications);
if (medications != null && !medications.isEmpty()) {
binding.recyclerMedication.setVisibility(View.VISIBLE);
binding.textEmptyMedications.setVisibility(View.GONE);
} else {
binding.recyclerMedication.setVisibility(View.GONE);
binding.textEmptyMedications.setVisibility(View.VISIBLE);
}
});
binding.fabAddMedication.setOnClickListener(v -> showMedicationDialog(null));
return binding.getRoot();
}
private void showMedicationDialog(Medication medication) {
MedicationDialog dialog = new MedicationDialog();
dialog.setMedicationToEdit(medication);
dialog.setListener(medicationToSave -> {
// If it's an edit, cancel old alarms first
if (medication != null && medication.time != null) {
String[] oldTimes = medication.time.split(",\\s*");
for (String t : oldTimes) {
if (t.isEmpty()) continue;
try {
int oldId = (medication.name + t).hashCode();
com.example.cuida.utils.AlarmScheduler.cancelAlarm(requireContext(), oldId);
} catch (Exception e) {}
}
}
if (medication == null) {
medicationViewModel.insert(medicationToSave);
} else {
medicationViewModel.update(medicationToSave);
}
String[] times = medicationToSave.time.split(",\\s*");
for (String t : times) {
if (t.isEmpty()) continue;
try {
String[] timeParts = t.split(":");
int hour = Integer.parseInt(timeParts[0]);
int minute = Integer.parseInt(timeParts[1]);
java.util.Calendar calendar = java.util.Calendar.getInstance();
calendar.set(java.util.Calendar.HOUR_OF_DAY, hour);
calendar.set(java.util.Calendar.MINUTE, minute);
calendar.set(java.util.Calendar.SECOND, 0);
if (calendar.getTimeInMillis() <= System.currentTimeMillis()) {
calendar.add(java.util.Calendar.DAY_OF_YEAR, 1);
}
String title = "Hora do Medicamento";
String msg = "É hora de tomar: " + medicationToSave.name + " (" + medicationToSave.dosage + ")";
int alarmId = (medicationToSave.name + t).hashCode();
com.example.cuida.utils.AlarmScheduler.scheduleAlarm(
requireContext(),
calendar.getTimeInMillis(),
title,
msg,
alarmId);
} catch (Exception e) {
e.printStackTrace();
}
}
dialog.dismiss();
});
dialog.setDeleteListener(medicationToDelete -> {
medicationViewModel.delete(medicationToDelete);
// Cancel all alarms for this medication
if (medicationToDelete.time != null) {
String[] times = medicationToDelete.time.split(",\\s*");
for (String t : times) {
if (t.isEmpty()) continue;
try {
int alarmId = (medicationToDelete.name + t).hashCode();
com.example.cuida.utils.AlarmScheduler.cancelAlarm(requireContext(), alarmId);
} catch (Exception e) {
e.printStackTrace();
}
}
}
});
dialog.show(getParentFragmentManager(), "MedicationDialog");
}
@Override
public void onDestroyView() {
super.onDestroyView();
binding = null;
}
}

View File

@@ -0,0 +1,118 @@
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 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 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);
db = FirebaseFirestore.getInstance();
auth = FirebaseAuth.getInstance();
fetchMedications();
}
private void fetchMedications() {
if (auth.getCurrentUser() == null)
return;
String userId = auth.getCurrentUser().getUid();
db.collection("medicamentos")
.whereEqualTo("userId", userId)
.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);
med.id = doc.getId(); // Ensure ID is set
meds.add(med);
}
}
// Sort locally to avoid needing a composite index in Firestore
meds.sort((m1, m2) -> {
if (m1.time == null && m2.time == null) return 0;
if (m1.time == null) return 1;
if (m2.time == null) return -1;
return m1.time.compareTo(m2.time);
});
allMedications.setValue(meds);
if (!meds.isEmpty()) {
nextMedication.setValue(meds.get(0));
} else {
nextMedication.setValue(null);
}
});
}
public LiveData<List<Medication>> getAllMedications() {
return allMedications;
}
public LiveData<Medication> getNextMedication() {
return nextMedication;
}
public void insert(Medication medication) {
if (auth.getCurrentUser() == null)
return;
String userId = auth.getCurrentUser().getUid();
medication.userId = userId;
db.collection("medicamentos")
.add(medication)
.addOnSuccessListener(documentReference -> Log.d("MedicationViewModel", "Medication added"))
.addOnFailureListener(e -> Log.w("MedicationViewModel", "Error adding medication", e));
}
public void update(Medication medication) {
if (auth.getCurrentUser() == null || medication.id == null)
return;
String userId = auth.getCurrentUser().getUid();
medication.userId = userId;
db.collection("medicamentos")
.document(medication.id)
.set(medication)
.addOnSuccessListener(aVoid -> Log.d("MedicationViewModel", "Medication updated"))
.addOnFailureListener(e -> Log.w("MedicationViewModel", "Error updating medication", e));
}
public void delete(Medication medication) {
if (auth.getCurrentUser() == null || medication.id == null)
return;
db.collection("medicamentos")
.document(medication.id)
.delete()
.addOnSuccessListener(aVoid -> Log.d("MedicationViewModel", "Medication deleted"))
.addOnFailureListener(e -> Log.w("MedicationViewModel", "Error deleting medication", e));
}
}

View File

@@ -0,0 +1,111 @@
<?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="wrap_content"
android:orientation="vertical"
android:padding="24dp">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/layout_med_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:hint="Nome do Medicamento"
android:layout_marginBottom="8dp">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/edit_med_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textCapWords" />
</com.google.android.material.textfield.TextInputLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
android:layout_marginBottom="4dp">
<TextView
android:text="Horários"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textSize="14sp"/>
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_add_time"
style="@style/Widget.MaterialComponents.Button.TextButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Adicionar"
android:padding="0dp"
android:minWidth="0dp"
android:minHeight="0dp"/>
</LinearLayout>
<com.google.android.material.chip.ChipGroup
android:id="@+id/chip_group_times"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:padding="4dp"/>
<TextView
android:text="Via de Administração"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="14sp"
android:layout_marginBottom="4dp"/>
<RadioGroup
android:id="@+id/radio_group_route"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp">
<RadioButton
android:id="@+id/radio_oral"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Via Oral (Pela boca)" />
<RadioButton
android:id="@+id/radio_topical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Via Tópica (Na pele)" />
<RadioButton
android:id="@+id/radio_inhalatory"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Via Inalatória (Pelo nariz/boca)" />
</RadioGroup>
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Notas (Opcional)"
android:layout_marginBottom="16dp">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/edit_med_notes"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textMultiLine"
android:minLines="2"/>
</com.google.android.material.textfield.TextInputLayout>
</LinearLayout>