369 lines
16 KiB
Java
369 lines
16 KiB
Java
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();
|
|
}
|
|
}
|
|
}
|