diff --git a/app/src/main/java/com/example/pap_teste/MinhasReservasActivity.java b/app/src/main/java/com/example/pap_teste/MinhasReservasActivity.java new file mode 100644 index 0000000..a2fa358 --- /dev/null +++ b/app/src/main/java/com/example/pap_teste/MinhasReservasActivity.java @@ -0,0 +1,117 @@ +package com.example.pap_teste; + +import android.content.Intent; +import android.os.Bundle; +import android.widget.Button; +import android.widget.Toast; + +import androidx.activity.EdgeToEdge; +import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; +import androidx.core.graphics.Insets; +import androidx.core.view.ViewCompat; +import androidx.core.view.WindowInsetsCompat; +import androidx.recyclerview.widget.RecyclerView; + +import com.example.pap_teste.models.Reserva; +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 java.util.ArrayList; +import java.util.List; + +public class MinhasReservasActivity extends AppCompatActivity { + + private RecyclerView rvMinhasReservas; + private ReservaAdapter adapter; + private final List reservaList = new ArrayList<>(); + private DatabaseReference databaseReference; + private String clientEmail; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + EdgeToEdge.enable(this); + setContentView(R.layout.activity_minhas_reservas); + ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.minhasReservasRoot), (v, insets) -> { + Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()); + v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom); + return insets; + }); + + clientEmail = getIntent().getStringExtra(MainActivity.EXTRA_EMAIL); + if (clientEmail == null) { + com.google.firebase.auth.FirebaseUser user = com.google.firebase.auth.FirebaseAuth.getInstance().getCurrentUser(); + if (user != null) { + clientEmail = user.getEmail(); + } + } + + // Fallback for testing if still null + if (clientEmail == null) { + clientEmail = "cliente@teste.com"; + } + + rvMinhasReservas = findViewById(R.id.rvMinhasReservas); + Button btnVoltar = findViewById(R.id.btnVoltar); + btnVoltar.setOnClickListener(v -> finish()); + + setupAdapter(); + loadReservations(); + } + + private void setupAdapter() { + adapter = new ReservaAdapter(reservaList, new ReservaAdapter.OnReservaActionListener() { + @Override + public void onCheckIn(Reserva reserva) { + Intent intent = new Intent(MinhasReservasActivity.this, CheckInAntecipadoActivity.class); + intent.putExtra("restaurant_email", reserva.getRestauranteEmail()); + startActivity(intent); + } + + @Override + public void onCancel(Reserva reserva) { + cancelReservation(reserva); + } + }); + rvMinhasReservas.setAdapter(adapter); + } + + private void loadReservations() { + databaseReference = FirebaseDatabase.getInstance().getReference("reservas"); + databaseReference.orderByChild("clienteEmail").equalTo(clientEmail) + .addValueEventListener(new ValueEventListener() { + @Override + public void onDataChange(@NonNull DataSnapshot snapshot) { + reservaList.clear(); + for (DataSnapshot dataSnapshot : snapshot.getChildren()) { + Reserva reserva = dataSnapshot.getValue(Reserva.class); + if (reserva != null) { + reservaList.add(reserva); + } + } + adapter.notifyDataSetChanged(); + } + + @Override + public void onCancelled(@NonNull DatabaseError error) { + Toast.makeText(MinhasReservasActivity.this, "Erro ao carregar reservas.", Toast.LENGTH_SHORT) + .show(); + } + }); + } + + 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(); + } + }); + } +} diff --git a/app/src/main/java/com/example/pap_teste/ReservaAdapter.java b/app/src/main/java/com/example/pap_teste/ReservaAdapter.java new file mode 100644 index 0000000..0c9b082 --- /dev/null +++ b/app/src/main/java/com/example/pap_teste/ReservaAdapter.java @@ -0,0 +1,82 @@ +package com.example.pap_teste; + +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +import com.example.pap_teste.models.Reserva; + +import java.util.List; + +public class ReservaAdapter extends RecyclerView.Adapter { + + public interface OnReservaActionListener { + void onCheckIn(Reserva reserva); + + void onCancel(Reserva reserva); + } + + private final List reservas; + private final OnReservaActionListener listener; + + public ReservaAdapter(List reservas, OnReservaActionListener listener) { + this.reservas = reservas; + this.listener = listener; + } + + @NonNull + @Override + public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_reserva_cliente, parent, false); + return new ViewHolder(view); + } + + @Override + public void onBindViewHolder(@NonNull ViewHolder holder, int position) { + Reserva reserva = reservas.get(position); + holder.txtRestaurante.setText(reserva.getRestauranteName()); + holder.txtDataHora.setText(reserva.getData() + " às " + reserva.getHora() + " • " + reserva.getPessoas() + "p"); + holder.txtStatus.setText("Estado: " + reserva.getEstado()); + + // Enable check-in only if confirmed + holder.btnCheckIn.setEnabled("Confirmada".equals(reserva.getEstado())); + + // Show cancel only if not concluded or already cancelled/refused + boolean canCancel = "Pendente".equals(reserva.getEstado()) || "Confirmada".equals(reserva.getEstado()); + holder.btnCancelar.setVisibility(canCancel ? View.VISIBLE : View.GONE); + + holder.btnCheckIn.setOnClickListener(v -> { + if (listener != null) + listener.onCheckIn(reserva); + }); + + holder.btnCancelar.setOnClickListener(v -> { + if (listener != null) + listener.onCancel(reserva); + }); + } + + @Override + public int getItemCount() { + return reservas.size(); + } + + public static class ViewHolder extends RecyclerView.ViewHolder { + TextView txtRestaurante, txtDataHora, txtStatus; + Button btnCheckIn, btnCancelar; + + public ViewHolder(@NonNull View itemView) { + super(itemView); + txtRestaurante = itemView.findViewById(R.id.txtReservaRestaurante); + txtDataHora = itemView.findViewById(R.id.txtReservaDataHora); + txtStatus = itemView.findViewById(R.id.txtReservaStatus); + btnCheckIn = itemView.findViewById(R.id.btnCheckIn); + btnCancelar = itemView.findViewById(R.id.btnCancelar); + } + } +} diff --git a/app/src/main/java/com/example/pap_teste/ReservationOptionAdapter.java b/app/src/main/java/com/example/pap_teste/ReservationOptionAdapter.java new file mode 100644 index 0000000..9f19a3a --- /dev/null +++ b/app/src/main/java/com/example/pap_teste/ReservationOptionAdapter.java @@ -0,0 +1,70 @@ +package com.example.pap_teste; + +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +import java.util.List; + +public class ReservationOptionAdapter extends RecyclerView.Adapter { + + public interface OnOptionSelectedListener { + void onOptionSelected(String option); + } + + private final List options; + private final OnOptionSelectedListener listener; + private int selectedPosition = -1; + + public ReservationOptionAdapter(List options, OnOptionSelectedListener listener) { + this.options = options; + this.listener = listener; + } + + @NonNull + @Override + public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_reservation_option, parent, false); + return new ViewHolder(view); + } + + @Override + public void onBindViewHolder(@NonNull ViewHolder holder, int position) { + String option = options.get(position); + holder.txtValue.setText(option); + + boolean isSelected = position == selectedPosition; + holder.cardRoot.setCardBackgroundColor(isSelected ? 0xFFFF6B6B : 0xFFFFFFFF); + holder.txtValue.setTextColor(isSelected ? 0xFFFFFFFF : 0xFF000000); + + holder.itemView.setOnClickListener(v -> { + int previousSelected = selectedPosition; + selectedPosition = holder.getAdapterPosition(); + notifyItemChanged(previousSelected); + notifyItemChanged(selectedPosition); + if (listener != null) { + listener.onOptionSelected(option); + } + }); + } + + @Override + public int getItemCount() { + return options.size(); + } + + public static class ViewHolder extends RecyclerView.ViewHolder { + TextView txtValue; + androidx.cardview.widget.CardView cardRoot; + + public ViewHolder(@NonNull View itemView) { + super(itemView); + txtValue = itemView.findViewById(R.id.txtOptionValue); + cardRoot = itemView.findViewById(R.id.cardOption); + } + } +} diff --git a/app/src/main/java/com/example/pap_teste/RestaurantAdapter.java b/app/src/main/java/com/example/pap_teste/RestaurantAdapter.java new file mode 100644 index 0000000..e620c34 --- /dev/null +++ b/app/src/main/java/com/example/pap_teste/RestaurantAdapter.java @@ -0,0 +1,81 @@ +package com.example.pap_teste; + +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageButton; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +import com.example.pap_teste.models.Restaurant; + +import java.util.List; + +public class RestaurantAdapter extends RecyclerView.Adapter { + + public interface OnRestaurantClickListener { + void onRestaurantClick(Restaurant restaurant); + } + + private final List restaurants; + private final OnRestaurantClickListener listener; + + public RestaurantAdapter(List restaurants, OnRestaurantClickListener listener) { + this.restaurants = restaurants; + this.listener = listener; + } + + @NonNull + @Override + public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_restaurant, parent, false); + return new ViewHolder(view); + } + + @Override + public void onBindViewHolder(@NonNull ViewHolder holder, int position) { + Restaurant restaurant = restaurants.get(position); + holder.txtName.setText(restaurant.getName()); + holder.txtCategory.setText(restaurant.getCategory()); + + updateFavoriteIcon(holder.btnFavorite, restaurant.isFavorite()); + + holder.btnFavorite.setOnClickListener(v -> { + restaurant.setFavorite(!restaurant.isFavorite()); + updateFavoriteIcon(holder.btnFavorite, restaurant.isFavorite()); + }); + + holder.itemView.setOnClickListener(v -> { + if (listener != null) { + listener.onRestaurantClick(restaurant); + } + }); + } + + private void updateFavoriteIcon(ImageButton btn, boolean isFavorite) { + if (isFavorite) { + btn.setImageResource(android.R.drawable.btn_star_big_on); + } else { + btn.setImageResource(android.R.drawable.btn_star_big_off); + } + } + + @Override + public int getItemCount() { + return restaurants.size(); + } + + public static class ViewHolder extends RecyclerView.ViewHolder { + TextView txtName, txtCategory; + ImageButton btnFavorite; + + public ViewHolder(@NonNull View itemView) { + super(itemView); + txtName = itemView.findViewById(R.id.txtRestaurantName); + txtCategory = itemView.findViewById(R.id.txtRestaurantCategory); + btnFavorite = itemView.findViewById(R.id.btnFavorite); + } + } +} diff --git a/app/src/main/java/com/example/pap_teste/models/Reserva.java b/app/src/main/java/com/example/pap_teste/models/Reserva.java new file mode 100644 index 0000000..be20023 --- /dev/null +++ b/app/src/main/java/com/example/pap_teste/models/Reserva.java @@ -0,0 +1,92 @@ +package com.example.pap_teste.models; + +public class Reserva { + private String id; + private String clienteEmail; + private String restauranteName; + private String restauranteEmail; + private String data; + private String hora; + private int pessoas; + private String estado; // Pendente, Confirmada, Concluída, Cancelada, Recusada + + public Reserva() { + // Required for Firebase + } + + public Reserva(String id, String clienteEmail, String restauranteName, String restauranteEmail, String data, + String hora, int pessoas, String estado) { + this.id = id; + this.clienteEmail = clienteEmail; + this.restauranteName = restauranteName; + this.restauranteEmail = restauranteEmail; + this.data = data; + this.hora = hora; + this.pessoas = pessoas; + this.estado = estado; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getClienteEmail() { + return clienteEmail; + } + + public void setClienteEmail(String clienteEmail) { + this.clienteEmail = clienteEmail; + } + + public String getRestauranteName() { + return restauranteName; + } + + public void setRestauranteName(String restauranteName) { + this.restauranteName = restauranteName; + } + + public String getRestauranteEmail() { + return restauranteEmail; + } + + public void setRestauranteEmail(String restauranteEmail) { + this.restauranteEmail = restauranteEmail; + } + + public String getData() { + return data; + } + + public void setData(String data) { + this.data = data; + } + + public String getHora() { + return hora; + } + + public void setHora(String hora) { + this.hora = hora; + } + + public int getPessoas() { + return pessoas; + } + + public void setPessoas(int pessoas) { + this.pessoas = pessoas; + } + + public String getEstado() { + return estado; + } + + public void setEstado(String estado) { + this.estado = estado; + } +} diff --git a/app/src/main/java/com/example/pap_teste/models/Restaurant.java b/app/src/main/java/com/example/pap_teste/models/Restaurant.java new file mode 100644 index 0000000..09e2e22 --- /dev/null +++ b/app/src/main/java/com/example/pap_teste/models/Restaurant.java @@ -0,0 +1,60 @@ +package com.example.pap_teste.models; + +public class Restaurant { + private String name; + private String category; + private String email; + private String address; + private boolean isFavorite; + + public Restaurant() { + // Required for Firebase + } + + public Restaurant(String name, String category, String email, boolean isFavorite) { + this.name = name; + this.category = category; + this.email = email; + this.isFavorite = isFavorite; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getCategory() { + return category; + } + + public void setCategory(String category) { + this.category = category; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + + public boolean isFavorite() { + return isFavorite; + } + + public void setFavorite(boolean favorite) { + isFavorite = favorite; + } +} diff --git a/app/src/main/res/drawable/cat_pizzas.png b/app/src/main/res/drawable/cat_pizzas.png new file mode 100644 index 0000000..7e058b8 Binary files /dev/null and b/app/src/main/res/drawable/cat_pizzas.png differ diff --git a/app/src/main/res/drawable/cat_sobremesas.png b/app/src/main/res/drawable/cat_sobremesas.png new file mode 100644 index 0000000..404ac6d Binary files /dev/null and b/app/src/main/res/drawable/cat_sobremesas.png differ diff --git a/app/src/main/res/layout/activity_minhas_reservas.xml b/app/src/main/res/layout/activity_minhas_reservas.xml new file mode 100644 index 0000000..d11d686 --- /dev/null +++ b/app/src/main/res/layout/activity_minhas_reservas.xml @@ -0,0 +1,48 @@ + + + +