This commit is contained in:
2026-03-17 09:17:07 +00:00
parent 2db6544284
commit 948921a424
12 changed files with 697 additions and 0 deletions

View File

@@ -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<Reserva> 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();
}
});
}
}

View File

@@ -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<ReservaAdapter.ViewHolder> {
public interface OnReservaActionListener {
void onCheckIn(Reserva reserva);
void onCancel(Reserva reserva);
}
private final List<Reserva> reservas;
private final OnReservaActionListener listener;
public ReservaAdapter(List<Reserva> 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);
}
}
}

View File

@@ -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<ReservationOptionAdapter.ViewHolder> {
public interface OnOptionSelectedListener {
void onOptionSelected(String option);
}
private final List<String> options;
private final OnOptionSelectedListener listener;
private int selectedPosition = -1;
public ReservationOptionAdapter(List<String> 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);
}
}
}

View File

@@ -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<RestaurantAdapter.ViewHolder> {
public interface OnRestaurantClickListener {
void onRestaurantClick(Restaurant restaurant);
}
private final List<Restaurant> restaurants;
private final OnRestaurantClickListener listener;
public RestaurantAdapter(List<Restaurant> 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);
}
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 732 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 548 KiB

View File

@@ -0,0 +1,48 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/minhasReservasRoot"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#F7F7F7"
tools:context=".MinhasReservasActivity">
<Button
android:id="@+id/btnVoltar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:text="Voltar"
android:textAllCaps="false"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/txtTituloMinhasReservas"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Minhas Reservas"
android:textColor="#000"
android:textSize="22sp"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/btnVoltar"
android:layout_marginTop="24dp" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rvMinhasReservas"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="16dp"
android:clipToPadding="false"
android:paddingBottom="16dp"
app:layout_constraintTop_toBottomOf="@id/txtTituloMinhasReservas"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -0,0 +1,73 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginVertical="8dp"
app:cardCornerRadius="16dp"
app:cardElevation="2dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:id="@+id/txtReservaRestaurante"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Nome do Restaurante"
android:textColor="#000"
android:textSize="18sp"
android:textStyle="bold" />
<TextView
android:id="@+id/txtReservaDataHora"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:text="Hoje às 20:00"
android:textColor="#757575"
android:textSize="14sp" />
<TextView
android:id="@+id/txtReservaStatus"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="Estado: Pendente"
android:textSize="14sp"
android:textStyle="bold" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:orientation="horizontal">
<Button
android:id="@+id/btnCheckIn"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginEnd="4dp"
android:text="Check-in"
android:textAllCaps="false"
android:background="@drawable/btn_primary"
android:textColor="#FFF" />
<Button
android:id="@+id/btnCancelar"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginStart="4dp"
android:text="Cancelar"
android:textAllCaps="false"
android:background="@drawable/btn_light_border"
android:textColor="#C62828" />
</LinearLayout>
</LinearLayout>
</androidx.cardview.widget.CardView>

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/cardOption"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp"
app:cardCornerRadius="12dp"
app:cardElevation="2dp"
app:cardBackgroundColor="#FFFFFF">
<TextView
android:id="@+id/txtOptionValue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingHorizontal="24dp"
android:paddingVertical="12dp"
android:text="Option"
android:textColor="#000"
android:textSize="14sp" />
</androidx.cardview.widget.CardView>

View File

@@ -0,0 +1,53 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginVertical="8dp"
app:cardCornerRadius="16dp"
app:cardElevation="2dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_toStartOf="@id/btnFavorite"
android:orientation="vertical">
<TextView
android:id="@+id/txtRestaurantName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Restaurant Name"
android:textColor="#000"
android:textSize="18sp"
android:textStyle="bold" />
<TextView
android:id="@+id/txtRestaurantCategory"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:text="Category"
android:textColor="#757575"
android:textSize="14sp" />
</LinearLayout>
<ImageButton
android:id="@+id/btnFavorite"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:background="?attr/selectableItemBackgroundBorderless"
android:padding="8dp"
android:scaleType="fitCenter"
android:src="@android:drawable/btn_star_big_off" />
</RelativeLayout>
</androidx.cardview.widget.CardView>