From 5226b032b0eda9659782be71239e9f16cdbf6d40 Mon Sep 17 00:00:00 2001 From: 230409 <230409@epvc.pt> Date: Mon, 4 May 2026 10:09:34 +0100 Subject: [PATCH] .. --- .../pap_teste/ClientDashboardActivity.java | 128 +++++++++--- .../pap_teste/DetalhesReservasActivity.java | 122 +++++++++--- .../pap_teste/ListaEsperaActivity.java | 16 +- .../res/layout/activity_client_dashboard.xml | 184 ++++++++++++++++-- 4 files changed, 382 insertions(+), 68 deletions(-) diff --git a/app/src/main/java/com/example/pap_teste/ClientDashboardActivity.java b/app/src/main/java/com/example/pap_teste/ClientDashboardActivity.java index 2448f9c..4e42ca2 100644 --- a/app/src/main/java/com/example/pap_teste/ClientDashboardActivity.java +++ b/app/src/main/java/com/example/pap_teste/ClientDashboardActivity.java @@ -38,15 +38,14 @@ public class ClientDashboardActivity extends AppCompatActivity { private ImageView imgProfile; private EditText etSearch; private ChipGroup chipGroupCategories; - private RecyclerView rvFeatured, rvMainRestaurants; + private RecyclerView rvFeatured, rvTopRated, rvPizzas, rvSushi, rvCarnes, rvMassas, rvSobremesas; private ProgressBar progressBar; - private View layoutFeatured, layoutAllRestaurants; + private View layoutFeatured, layoutTopRated, layoutPizzas, layoutSushi, layoutCarnes, layoutMassas, layoutSobremesas; private List allRestaurants = new ArrayList<>(); private List filteredRestaurants = new ArrayList<>(); - private RestaurantAdapter mainAdapter; - private FeaturedRestaurantAdapter featuredAdapter; + private FeaturedRestaurantAdapter featuredAdapter, topRatedAdapter, pizzasAdapter, sushiAdapter, carnesAdapter, massasAdapter, sobremesasAdapter; private final String[] CATEGORIES = { "Tudo", "Carnes", "Massas", "Sushi", "Pizzas", "Sobremesas" }; private String currentCategoryFilter = "Tudo"; @@ -83,30 +82,53 @@ public class ClientDashboardActivity extends AppCompatActivity { etSearch = findViewById(R.id.etSearch); chipGroupCategories = findViewById(R.id.chipGroupCategories); rvFeatured = findViewById(R.id.rvFeatured); - rvMainRestaurants = findViewById(R.id.rvMainRestaurants); + rvTopRated = findViewById(R.id.rvTopRated); + rvPizzas = findViewById(R.id.rvPizzas); + rvSushi = findViewById(R.id.rvSushi); + rvCarnes = findViewById(R.id.rvCarnes); + rvMassas = findViewById(R.id.rvMassas); + rvSobremesas = findViewById(R.id.rvSobremesas); + progressBar = findViewById(R.id.progressBar); + layoutFeatured = findViewById(R.id.layoutFeatured); - layoutAllRestaurants = findViewById(R.id.layoutAllRestaurants); + layoutTopRated = findViewById(R.id.layoutTopRated); + layoutPizzas = findViewById(R.id.layoutPizzas); + layoutSushi = findViewById(R.id.layoutSushi); + layoutCarnes = findViewById(R.id.layoutCarnes); + layoutMassas = findViewById(R.id.layoutMassas); + layoutSobremesas = findViewById(R.id.layoutSobremesas); rvFeatured.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false)); - rvMainRestaurants.setLayoutManager(new LinearLayoutManager(this)); + rvTopRated.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false)); + rvPizzas.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false)); + rvSushi.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false)); + rvCarnes.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false)); + rvMassas.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false)); + rvSobremesas.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false)); // Click listener for restaurants to open booking flow RestaurantAdapter.OnRestaurantClickListener clickListener = restaurant -> { Intent intent = new Intent(this, ExplorarRestaurantesActivity.class); - // Reusing existing activity for details if needed, or pass data to - // NovaReservaActivity - // We pass the filter so it can maybe open directly or we just pass restaurant - // email intent.putExtra("category_filter", restaurant.getCategory()); startActivity(intent); }; featuredAdapter = new FeaturedRestaurantAdapter(new ArrayList<>(), clickListener); - mainAdapter = new RestaurantAdapter(filteredRestaurants, clickListener); + topRatedAdapter = new FeaturedRestaurantAdapter(new ArrayList<>(), clickListener); + pizzasAdapter = new FeaturedRestaurantAdapter(new ArrayList<>(), clickListener); + sushiAdapter = new FeaturedRestaurantAdapter(new ArrayList<>(), clickListener); + carnesAdapter = new FeaturedRestaurantAdapter(new ArrayList<>(), clickListener); + massasAdapter = new FeaturedRestaurantAdapter(new ArrayList<>(), clickListener); + sobremesasAdapter = new FeaturedRestaurantAdapter(new ArrayList<>(), clickListener); rvFeatured.setAdapter(featuredAdapter); - rvMainRestaurants.setAdapter(mainAdapter); + rvTopRated.setAdapter(topRatedAdapter); + rvPizzas.setAdapter(pizzasAdapter); + rvSushi.setAdapter(sushiAdapter); + rvCarnes.setAdapter(carnesAdapter); + rvMassas.setAdapter(massasAdapter); + rvSobremesas.setAdapter(sobremesasAdapter); // Click listener for profile picture in the header findViewById(R.id.cardProfile).setOnClickListener(v -> { @@ -163,7 +185,12 @@ public class ClientDashboardActivity extends AppCompatActivity { private void fetchRestaurants() { progressBar.setVisibility(View.VISIBLE); layoutFeatured.setVisibility(View.GONE); - layoutAllRestaurants.setVisibility(View.GONE); + layoutTopRated.setVisibility(View.GONE); + layoutPizzas.setVisibility(View.GONE); + layoutSushi.setVisibility(View.GONE); + layoutCarnes.setVisibility(View.GONE); + layoutMassas.setVisibility(View.GONE); + layoutSobremesas.setVisibility(View.GONE); DatabaseReference usersRef = FirebaseDatabase.getInstance().getReference("Restaurantes"); usersRef.addListenerForSingleValueEvent(new ValueEventListener() { @@ -281,24 +308,73 @@ public class ClientDashboardActivity extends AppCompatActivity { } } - mainAdapter.notifyDataSetChanged(); - - // Update featured (just the first 3 for demo, or based on a specific logic) + // Listas por categorias List featuredList = new ArrayList<>(); - for (int i = 0; i < Math.min(3, filteredRestaurants.size()); i++) { - featuredList.add(filteredRestaurants.get(i)); + List topRatedList = new ArrayList<>(); + List pizzasList = new ArrayList<>(); + List sushiList = new ArrayList<>(); + List carnesList = new ArrayList<>(); + List massasList = new ArrayList<>(); + List sobremesasList = new ArrayList<>(); + + // Preencher Destaques e Melhores + for (int i = 0; i < filteredRestaurants.size(); i++) { + Restaurant r = filteredRestaurants.get(i); + + // Destaques (3 primeiros aleatórios/ordem atual) + if (featuredList.size() < 3) { + featuredList.add(r); + } + + // Melhor Avaliados (>= 3.0 estrelas) + if (r.getRatingAvg() != null && r.getRatingAvg() >= 3.0) { + topRatedList.add(r); + } + + // Distribuir pelas categorias baseadas na String + String cat = r.getCategory() != null ? r.getCategory().toLowerCase() : ""; + if (cat.contains("pizza")) { + pizzasList.add(r); + } else if (cat.contains("sushi")) { + sushiList.add(r); + } else if (cat.contains("carne")) { + carnesList.add(r); + } else if (cat.contains("massa")) { + massasList.add(r); + } else if (cat.contains("sobremesa")) { + sobremesasList.add(r); + } } - featuredAdapter = new FeaturedRestaurantAdapter(featuredList, - mainAdapter instanceof RestaurantAdapter ? restaurant -> { - Intent intent = new Intent(this, ExplorarRestaurantesActivity.class); - intent.putExtra("category_filter", restaurant.getCategory()); - startActivity(intent); - } : null); + RestaurantAdapter.OnRestaurantClickListener clickListener = restaurant -> { + Intent intent = new Intent(this, ExplorarRestaurantesActivity.class); + intent.putExtra("category_filter", restaurant.getCategory()); + startActivity(intent); + }; + + featuredAdapter = new FeaturedRestaurantAdapter(featuredList, clickListener); + topRatedAdapter = new FeaturedRestaurantAdapter(topRatedList, clickListener); + pizzasAdapter = new FeaturedRestaurantAdapter(pizzasList, clickListener); + sushiAdapter = new FeaturedRestaurantAdapter(sushiList, clickListener); + carnesAdapter = new FeaturedRestaurantAdapter(carnesList, clickListener); + massasAdapter = new FeaturedRestaurantAdapter(massasList, clickListener); + sobremesasAdapter = new FeaturedRestaurantAdapter(sobremesasList, clickListener); + rvFeatured.setAdapter(featuredAdapter); + rvTopRated.setAdapter(topRatedAdapter); + rvPizzas.setAdapter(pizzasAdapter); + rvSushi.setAdapter(sushiAdapter); + rvCarnes.setAdapter(carnesAdapter); + rvMassas.setAdapter(massasAdapter); + rvSobremesas.setAdapter(sobremesasAdapter); layoutFeatured.setVisibility(featuredList.isEmpty() ? View.GONE : View.VISIBLE); - layoutAllRestaurants.setVisibility(filteredRestaurants.isEmpty() ? View.GONE : View.VISIBLE); + layoutTopRated.setVisibility(topRatedList.isEmpty() ? View.GONE : View.VISIBLE); + layoutPizzas.setVisibility(pizzasList.isEmpty() ? View.GONE : View.VISIBLE); + layoutSushi.setVisibility(sushiList.isEmpty() ? View.GONE : View.VISIBLE); + layoutCarnes.setVisibility(carnesList.isEmpty() ? View.GONE : View.VISIBLE); + layoutMassas.setVisibility(massasList.isEmpty() ? View.GONE : View.VISIBLE); + layoutSobremesas.setVisibility(sobremesasList.isEmpty() ? View.GONE : View.VISIBLE); } private String normalizeString(String str) { diff --git a/app/src/main/java/com/example/pap_teste/DetalhesReservasActivity.java b/app/src/main/java/com/example/pap_teste/DetalhesReservasActivity.java index bd2b8a8..61e3c5d 100644 --- a/app/src/main/java/com/example/pap_teste/DetalhesReservasActivity.java +++ b/app/src/main/java/com/example/pap_teste/DetalhesReservasActivity.java @@ -118,8 +118,8 @@ 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())) { + mostrarMesasDisponiveis(); + } else if (item.getEstado() != null && item.getEstado().startsWith("Confirmada")) { atualizarEstadoSelecionado("Concluída"); } }); @@ -134,6 +134,80 @@ 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 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")) { + // Verifica se a mesa tem capacidade suficiente para a reserva + if (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 ou com capacidade suficiente para esta reserva. Deseja confirmar a reserva mesmo assim (sem atribuir mesa)?") + .setPositiveButton("Sim, aceitar", (dialog, which) -> atualizarEstadoSelecionado("Confirmada")) + .setNegativeButton("Cancelar", 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("Avançar sem mesa", (dialog, which) -> atualizarEstadoSelecionado("Confirmada")) + .setNeutralButton("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() + ")"; + databaseReference.child(reserva.getId()).child("estado").setValue(novoEstado).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(); + txtMensagem.setText(String.format("Reserva de %s confirmada na Mesa %d.", reserva.getClienteEmail(), mesa.getNumero())); + reserva.setEstado(novoEstado); + mostrarDetalhe(reserva); + }); + } else { + Toast.makeText(this, "Erro ao confirmar reserva.", Toast.LENGTH_SHORT).show(); + } + }); + } + private void showRecusarDialog() { if (selectedIndex < 0) return; @@ -218,29 +292,27 @@ public class DetalhesReservasActivity extends AppCompatActivity { return; } - switch (item.getEstado()) { - case "Pendente": - btnConfirmar.setText("Confirmar"); - btnConfirmar.setVisibility(android.view.View.VISIBLE); - 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 - break; + if (item.getEstado() == null) return; + + if (item.getEstado().equals("Pendente")) { + btnConfirmar.setText("Confirmar"); + btnConfirmar.setVisibility(android.view.View.VISIBLE); + btnRecusar.setVisibility(android.view.View.VISIBLE); + btnApagar.setVisibility(android.view.View.GONE); + } else if (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 if (item.getEstado().equals("Concluída")) { + btnConfirmar.setVisibility(android.view.View.GONE); + btnRecusar.setVisibility(android.view.View.GONE); + btnApagar.setVisibility(android.view.View.VISIBLE); + } else { + // Recusada or Cancelada + btnConfirmar.setVisibility(android.view.View.GONE); + btnRecusar.setVisibility(android.view.View.GONE); + btnApagar.setVisibility(android.view.View.VISIBLE); } } diff --git a/app/src/main/java/com/example/pap_teste/ListaEsperaActivity.java b/app/src/main/java/com/example/pap_teste/ListaEsperaActivity.java index 4e4cf27..7915511 100644 --- a/app/src/main/java/com/example/pap_teste/ListaEsperaActivity.java +++ b/app/src/main/java/com/example/pap_teste/ListaEsperaActivity.java @@ -106,17 +106,20 @@ public class ListaEsperaActivity extends AppCompatActivity { 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")) { - m.setId(ds.getKey()); - mesasLivres.add(m); + // Opcional: Filtra pela capacidade da mesa + if (m.getCapacidade() >= item.getPessoas()) { + m.setId(ds.getKey()); + mesasLivres.add(m); + } } } 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)?") - .setPositiveButton("Sim", (dialog, which) -> atualizarEstadoSelecionado("Confirmada")) - .setNegativeButton("Não", null) + .setMessage("Não há mesas livres registadas ou com capacidade suficiente para a reserva. Deseja confirmar a reserva mesmo assim (sem mesa atribuída)?") + .setPositiveButton("Sim, aceitar", (dialog, which) -> atualizarEstadoSelecionado("Confirmada")) + .setNegativeButton("Cancelar", null) .show(); return; } @@ -133,7 +136,8 @@ public class ListaEsperaActivity extends AppCompatActivity { com.example.pap_teste.models.Mesa selecionada = mesasLivres.get(which); confirmarReservaComMesa(item, selecionada); }) - .setNegativeButton("Cancelar", null) + .setNegativeButton("Avançar sem mesa", (dialog, which) -> atualizarEstadoSelecionado("Confirmada")) + .setNeutralButton("Cancelar", null) .show(); } diff --git a/app/src/main/res/layout/activity_client_dashboard.xml b/app/src/main/res/layout/activity_client_dashboard.xml index 1f7b042..04af6aa 100644 --- a/app/src/main/res/layout/activity_client_dashboard.xml +++ b/app/src/main/res/layout/activity_client_dashboard.xml @@ -8,7 +8,7 @@ android:background="@color/colorBackground" tools:context=".ClientDashboardActivity"> - - + - + + tools:listitem="@layout/item_restaurant_featured" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - +