This commit is contained in:
2026-06-15 14:12:03 +01:00
parent eaa3d86fc9
commit 995d23ac7a
5 changed files with 166 additions and 27 deletions

View File

@@ -118,9 +118,9 @@ public class DetalhesReservasActivity extends AppCompatActivity {
btnConfirmar.setOnClickListener(v -> {
com.example.pap_teste.models.Reserva item = reservas.get(selectedIndex);
if ("Pendente".equals(item.getEstado())) {
atualizarEstadoSelecionado("Confirmada");
} else if ("Confirmada".equals(item.getEstado())) {
atualizarEstadoSelecionado("Concluída");
mostrarMesasDisponiveis();
} else if ("Confirmada".equals(item.getEstado()) || item.getEstado().startsWith("Confirmada (Mesa")) {
showConcluirDialog();
}
});
}
@@ -134,6 +134,97 @@ public class DetalhesReservasActivity extends AppCompatActivity {
}
}
private void mostrarMesasDisponiveis() {
if (selectedIndex < 0 || selectedIndex >= reservas.size()) {
Toast.makeText(this, "Selecione uma reserva.", Toast.LENGTH_SHORT).show();
return;
}
com.example.pap_teste.models.Reserva item = reservas.get(selectedIndex);
com.google.firebase.database.DatabaseReference mesasRef = com.google.firebase.database.FirebaseDatabase.getInstance().getReference("Mesas");
mesasRef.orderByChild("restauranteEmail").equalTo(restaurantEmail).addListenerForSingleValueEvent(new com.google.firebase.database.ValueEventListener() {
@Override
public void onDataChange(@androidx.annotation.NonNull com.google.firebase.database.DataSnapshot snapshot) {
List<com.example.pap_teste.models.Mesa> mesasLivres = new ArrayList<>();
for (com.google.firebase.database.DataSnapshot ds : snapshot.getChildren()) {
com.example.pap_teste.models.Mesa m = ds.getValue(com.example.pap_teste.models.Mesa.class);
if (m != null && m.getEstado() != null && m.getEstado().equalsIgnoreCase("Livre") && m.getCapacidade() >= item.getPessoas()) {
m.setId(ds.getKey());
mesasLivres.add(m);
}
}
if (mesasLivres.isEmpty()) {
new androidx.appcompat.app.AlertDialog.Builder(DetalhesReservasActivity.this)
.setTitle("Sem mesas disponíveis")
.setMessage("Não há mesas livres com capacidade suficiente para " + item.getPessoas() + " pessoas. Deseja confirmar a reserva mesmo assim (sem mesa atribuída)?")
.setPositiveButton("Sim", (dialog, which) -> atualizarEstadoSelecionado("Confirmada", null))
.setNegativeButton("Não", null)
.show();
return;
}
String[] mesaOptions = new String[mesasLivres.size()];
for (int i = 0; i < mesasLivres.size(); i++) {
com.example.pap_teste.models.Mesa m = mesasLivres.get(i);
mesaOptions[i] = String.format("Mesa %d (%d lugares)", m.getNumero(), m.getCapacidade());
}
new androidx.appcompat.app.AlertDialog.Builder(DetalhesReservasActivity.this)
.setTitle("Atribuir Mesa")
.setItems(mesaOptions, (dialog, which) -> {
com.example.pap_teste.models.Mesa selecionada = mesasLivres.get(which);
confirmarReservaComMesa(item, selecionada);
})
.setNegativeButton("Cancelar", null)
.show();
}
@Override
public void onCancelled(@androidx.annotation.NonNull com.google.firebase.database.DatabaseError error) {
Toast.makeText(DetalhesReservasActivity.this, "Erro ao carregar mesas.", Toast.LENGTH_SHORT).show();
}
});
}
private void confirmarReservaComMesa(com.example.pap_teste.models.Reserva reserva, com.example.pap_teste.models.Mesa mesa) {
String novoEstado = "Confirmada (Mesa " + mesa.getNumero() + ")";
java.util.Map<String, Object> updates = new java.util.HashMap<>();
updates.put("estado", novoEstado);
updates.put("motivo", null); // limpar possível motivo antigo
databaseReference.child(reserva.getId()).updateChildren(updates).addOnCompleteListener(task -> {
if (task.isSuccessful()) {
com.google.firebase.database.FirebaseDatabase.getInstance().getReference("Mesas").child(mesa.getId()).child("estado").setValue("Reservada")
.addOnCompleteListener(t2 -> {
Toast.makeText(this, "Reserva aceite e mesa atribuída com sucesso.", Toast.LENGTH_SHORT).show();
reserva.setEstado(novoEstado);
reserva.setMotivo(null);
mostrarDetalhe(reserva);
});
} else {
Toast.makeText(this, "Erro ao confirmar reserva.", Toast.LENGTH_SHORT).show();
}
});
}
private void showConcluirDialog() {
if (selectedIndex < 0) return;
android.widget.EditText input = new android.widget.EditText(this);
input.setHint("Notas de conclusão (opcional)");
new androidx.appcompat.app.AlertDialog.Builder(this)
.setTitle("Concluir Reserva")
.setMessage("Deseja adicionar alguma nota ao concluir esta reserva?")
.setView(input)
.setPositiveButton("Concluir", (dialog, which) -> {
String motivo = input.getText().toString();
atualizarEstadoSelecionado("Concluída", motivo.isEmpty() ? null : motivo);
})
.setNegativeButton("Cancelar", null)
.show();
}
private void showRecusarDialog() {
if (selectedIndex < 0)
return;
@@ -142,7 +233,7 @@ public class DetalhesReservasActivity extends AppCompatActivity {
new androidx.appcompat.app.AlertDialog.Builder(this)
.setTitle("Motivo da Recusa")
.setItems(motivos, (dialog, which) -> {
atualizarEstadoSelecionado("Recusada (" + motivos[which] + ")");
atualizarEstadoSelecionado("Recusada", motivos[which]);
})
.setNegativeButton("Voltar", null)
.show();
@@ -186,17 +277,27 @@ public class DetalhesReservasActivity extends AppCompatActivity {
toggleButtons(null);
}
private void atualizarEstadoSelecionado(String novoEstado) {
private void atualizarEstadoSelecionado(String novoEstado, String motivo) {
if (selectedIndex < 0 || selectedIndex >= reservas.size()) {
Toast.makeText(this, "Selecione uma reserva para atualizar.", Toast.LENGTH_SHORT).show();
return;
}
com.example.pap_teste.models.Reserva item = reservas.get(selectedIndex);
databaseReference.child(item.getId()).child("estado").setValue(novoEstado).addOnCompleteListener(task -> {
java.util.Map<String, Object> updates = new java.util.HashMap<>();
updates.put("estado", novoEstado);
if (motivo != null && !motivo.isEmpty()) {
updates.put("motivo", motivo);
} else {
updates.put("motivo", null);
}
databaseReference.child(item.getId()).updateChildren(updates).addOnCompleteListener(task -> {
if (task.isSuccessful()) {
txtMensagem
.setText(String.format("Reserva de %s marcada como %s.", item.getClienteEmail(), novoEstado));
item.setEstado(novoEstado);
item.setMotivo(motivo);
mostrarDetalhe(item);
}
});
@@ -206,7 +307,13 @@ public class DetalhesReservasActivity extends AppCompatActivity {
txtInfo.setText(String.format("%s • %s • %s • %dp", item.getClienteEmail(), item.getRestauranteName(),
item.getHora(), item.getPessoas()));
txtNotas.setText("Data: " + item.getData());
txtEstado.setText(String.format("Estado: %s", item.getEstado()));
String estadoTexto = item.getEstado();
if (item.getMotivo() != null && !item.getMotivo().isEmpty()) {
estadoTexto += " (" + item.getMotivo() + ")";
}
txtEstado.setText(String.format("Estado: %s", estadoTexto));
toggleButtons(item);
}
@@ -225,21 +332,23 @@ public class DetalhesReservasActivity extends AppCompatActivity {
btnRecusar.setVisibility(android.view.View.VISIBLE);
btnApagar.setVisibility(android.view.View.GONE);
break;
case "Confirmada":
btnConfirmar.setText("Concluir");
btnConfirmar.setVisibility(android.view.View.VISIBLE);
btnRecusar.setVisibility(android.view.View.VISIBLE); // Still allow refusal
btnApagar.setVisibility(android.view.View.GONE);
break;
case "Concluída":
btnConfirmar.setVisibility(android.view.View.GONE);
btnRecusar.setVisibility(android.view.View.GONE);
btnApagar.setVisibility(android.view.View.VISIBLE);
break;
default: // Recusada or Cancelada
btnConfirmar.setVisibility(android.view.View.GONE);
btnRecusar.setVisibility(android.view.View.GONE);
btnApagar.setVisibility(android.view.View.VISIBLE); // Allow deleting refused ones as well
default:
if (item.getEstado() != null && item.getEstado().startsWith("Confirmada")) {
btnConfirmar.setText("Concluir");
btnConfirmar.setVisibility(android.view.View.VISIBLE);
btnRecusar.setVisibility(android.view.View.VISIBLE); // Still allow refusal
btnApagar.setVisibility(android.view.View.GONE);
} else {
// Recusada or Cancelada
btnConfirmar.setVisibility(android.view.View.GONE);
btnRecusar.setVisibility(android.view.View.GONE);
btnApagar.setVisibility(android.view.View.VISIBLE); // Allow deleting refused ones as well
}
break;
}
}

View File

@@ -105,7 +105,7 @@ public class ListaEsperaActivity extends AppCompatActivity {
List<com.example.pap_teste.models.Mesa> mesasLivres = new ArrayList<>();
for (DataSnapshot ds : snapshot.getChildren()) {
com.example.pap_teste.models.Mesa m = ds.getValue(com.example.pap_teste.models.Mesa.class);
if (m != null && m.getEstado() != null && m.getEstado().equalsIgnoreCase("Livre")) {
if (m != null && m.getEstado() != null && m.getEstado().equalsIgnoreCase("Livre") && m.getCapacidade() >= item.getPessoas()) {
m.setId(ds.getKey());
mesasLivres.add(m);
}
@@ -114,7 +114,7 @@ public class ListaEsperaActivity extends AppCompatActivity {
if (mesasLivres.isEmpty()) {
new androidx.appcompat.app.AlertDialog.Builder(ListaEsperaActivity.this)
.setTitle("Sem mesas disponíveis")
.setMessage("Não há mesas livres registadas. Deseja confirmar a reserva mesmo assim (sem lugar reservado)?")
.setMessage("Não há mesas livres com capacidade suficiente para " + item.getPessoas() + " pessoas. Deseja confirmar a reserva mesmo assim (sem lugar reservado)?")
.setPositiveButton("Sim", (dialog, which) -> atualizarEstadoSelecionado("Confirmada"))
.setNegativeButton("Não", null)
.show();

View File

@@ -120,13 +120,29 @@ public class MinhasReservasActivity extends AppCompatActivity {
}
private void cancelReservation(Reserva reserva) {
databaseReference.child(reserva.getId()).child("estado").setValue("Cancelada")
.addOnCompleteListener(task -> {
if (task.isSuccessful()) {
Toast.makeText(this, "Reserva cancelada.", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "Erro ao cancelar reserva.", Toast.LENGTH_SHORT).show();
android.widget.EditText input = new android.widget.EditText(this);
input.setHint("Motivo do cancelamento (opcional)");
new androidx.appcompat.app.AlertDialog.Builder(this)
.setTitle("Cancelar Reserva")
.setMessage("Deseja indicar o motivo do cancelamento?")
.setView(input)
.setPositiveButton("Confirmar", (dialog, which) -> {
String motivo = input.getText().toString();
java.util.Map<String, Object> updates = new java.util.HashMap<>();
updates.put("estado", "Cancelada");
if (!motivo.isEmpty()) {
updates.put("motivo", motivo);
}
});
databaseReference.child(reserva.getId()).updateChildren(updates)
.addOnCompleteListener(task -> {
if (task.isSuccessful()) {
Toast.makeText(this, "Reserva cancelada.", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "Erro ao cancelar reserva.", Toast.LENGTH_SHORT).show();
}
});
})
.setNegativeButton("Voltar", null)
.show();
}
}

View File

@@ -64,7 +64,7 @@ public class ReservationNotificationService extends Service {
Reserva reserva = snapshot.getValue(Reserva.class);
if (reserva != null && currentUserEmail.equals(reserva.getClienteEmail())) {
String estado = reserva.getEstado();
if (estado != null && (estado.startsWith("Confirmada") || estado.equals("Recusada"))) {
if (estado != null && (estado.startsWith("Confirmada") || estado.equals("Recusada") || estado.equals("Concluída") || estado.equals("Cancelada"))) {
sendNotification(reserva);
}
}
@@ -95,11 +95,16 @@ public class ReservationNotificationService extends Service {
String title = "Atualização de Reserva";
String message = "A sua reserva no " + reserva.getRestauranteName() + " foi " + reserva.getEstado().toLowerCase() + ".";
if (reserva.getMotivo() != null && !reserva.getMotivo().isEmpty()) {
message += " Motivo: " + reserva.getMotivo();
}
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
.setSmallIcon(R.drawable.na_mesa) // Assuming na_mesa is a valid drawable
.setContentTitle(title)
.setContentText(message)
.setStyle(new NotificationCompat.BigTextStyle().bigText(message))
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setContentIntent(pendingIntent)
.setAutoCancel(true);

View File

@@ -9,6 +9,7 @@ public class Reserva {
private String hora;
private int pessoas;
private String estado; // Pendente, Confirmada, Concluída, Cancelada, Recusada
private String motivo;
public Reserva() {
// Required for Firebase
@@ -89,4 +90,12 @@ public class Reserva {
public void setEstado(String estado) {
this.estado = estado;
}
public String getMotivo() {
return motivo;
}
public void setMotivo(String motivo) {
this.motivo = motivo;
}
}