From 3d817d0b8104856a8145d46106a3ee5c07b9c910 Mon Sep 17 00:00:00 2001
From: 230409 <230409@epvc.pt>
Date: Mon, 11 May 2026 14:54:38 +0100
Subject: [PATCH] ..
---
app/build.gradle.kts | 9 +-
app/src/main/AndroidManifest.xml | 42 +-
.../pap_teste/AccountCreatedActivity.java | 8 +-
.../pap_teste/LocalReservaAdapter.java | 67 +++
.../com/example/pap_teste/MainActivity.java | 6 +-
.../pap_teste/MyReservationsFragment.java | 75 ++--
.../pap_teste/NovaReservaActivity.java | 422 ++++++++----------
.../example/pap_teste/OnboardingActivity.java | 3 +-
.../example/pap_teste/ProfileFragment.java | 1 +
.../com/example/pap_teste/SplashActivity.java | 36 ++
.../pap_teste/TableSelectionAdapter.java | 87 ++++
.../example/pap_teste/data/AppDatabase.java | 24 +
.../pap_teste/data/ReservationDao.java | 29 ++
.../pap_teste/models/LocalReservation.java | 51 +++
.../com/example/pap_teste/models/Reserva.java | 39 +-
.../viewmodels/ReservationViewModel.java | 53 +++
.../main/res/layout/activity_nova_reserva.xml | 40 ++
app/src/main/res/layout/activity_splash.xml | 47 ++
.../main/res/layout/item_reserva_local.xml | 96 ++++
app/src/main/res/layout/item_table.xml | 48 ++
gradle/libs.versions.toml | 4 +
21 files changed, 875 insertions(+), 312 deletions(-)
create mode 100644 app/src/main/java/com/example/pap_teste/LocalReservaAdapter.java
create mode 100644 app/src/main/java/com/example/pap_teste/SplashActivity.java
create mode 100644 app/src/main/java/com/example/pap_teste/TableSelectionAdapter.java
create mode 100644 app/src/main/java/com/example/pap_teste/data/AppDatabase.java
create mode 100644 app/src/main/java/com/example/pap_teste/data/ReservationDao.java
create mode 100644 app/src/main/java/com/example/pap_teste/models/LocalReservation.java
create mode 100644 app/src/main/java/com/example/pap_teste/viewmodels/ReservationViewModel.java
create mode 100644 app/src/main/res/layout/activity_splash.xml
create mode 100644 app/src/main/res/layout/item_reserva_local.xml
create mode 100644 app/src/main/res/layout/item_table.xml
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index ad20d54..750a133 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -5,12 +5,12 @@ plugins {
android {
namespace = "com.example.pap_teste"
- compileSdk = 36
+ compileSdk = 35
defaultConfig {
applicationId = "com.example.pap_teste"
minSdk = 24
- targetSdk = 36
+ targetSdk = 35
versionCode = 1
versionName = "1.0"
@@ -44,6 +44,11 @@ dependencies {
implementation(libs.firebase.database)
implementation(libs.glide)
implementation(libs.firebase.storage)
+
+ // Room
+ implementation(libs.room.runtime)
+ annotationProcessor(libs.room.compiler)
+
testImplementation(libs.junit)
androidTestImplementation(libs.ext.junit)
androidTestImplementation(libs.espresso.core)
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index fa7d6df..a768316 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -27,7 +27,7 @@
@@ -35,6 +35,10 @@
+
+
@@ -50,6 +54,42 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/example/pap_teste/AccountCreatedActivity.java b/app/src/main/java/com/example/pap_teste/AccountCreatedActivity.java
index e23c3c9..65fc420 100644
--- a/app/src/main/java/com/example/pap_teste/AccountCreatedActivity.java
+++ b/app/src/main/java/com/example/pap_teste/AccountCreatedActivity.java
@@ -1,5 +1,7 @@
package com.example.pap_teste;
+import static android.content.Intent.getIntent;
+
import android.content.Intent;
import android.os.Bundle;
import android.widget.Button;
@@ -50,13 +52,13 @@ public class AccountCreatedActivity extends AppCompatActivity {
this,
isEstablishment ? EstablishmentDashboardActivity.class : ClientDashboardActivity.class
);
- nextScreen.putExtra(MainActivity.EXTRA_ACTION_MODE, MainActivity.AccountAction.CRIAR.name());
+ // nextScreen.putExtra(MainActivity.EXTRA_ACTION_MODE, MainActivity.AccountAction.CRIAR.name());
nextScreen.putExtra(MainActivity.EXTRA_DISPLAY_NAME, displayName);
nextScreen.putExtra(MainActivity.EXTRA_EMAIL, email);
nextScreen.putExtra(MainActivity.EXTRA_ACCOUNT_TYPE, accountType);
nextScreen.putExtra(MainActivity.EXTRA_ROLE, role);
- startActivity(nextScreen);
- finish();
+ //startActivity(nextScreen);
+ //finish();
});
if (btnBack != null) {
diff --git a/app/src/main/java/com/example/pap_teste/LocalReservaAdapter.java b/app/src/main/java/com/example/pap_teste/LocalReservaAdapter.java
new file mode 100644
index 0000000..b956163
--- /dev/null
+++ b/app/src/main/java/com/example/pap_teste/LocalReservaAdapter.java
@@ -0,0 +1,67 @@
+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 com.example.pap_teste.models.LocalReservation;
+import com.google.android.material.button.MaterialButton;
+import com.google.android.material.chip.Chip;
+import java.util.List;
+
+public class LocalReservaAdapter extends RecyclerView.Adapter {
+
+ private final List reservations;
+ private final OnActionListener listener;
+
+ public interface OnActionListener {
+ void onCancel(LocalReservation reservation);
+ void onEdit(LocalReservation reservation);
+ }
+
+ public LocalReservaAdapter(List reservations, OnActionListener listener) {
+ this.reservations = reservations;
+ this.listener = listener;
+ }
+
+ @NonNull
+ @Override
+ public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_reserva_local, parent, false);
+ return new ViewHolder(view);
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
+ LocalReservation res = reservations.get(position);
+ holder.restaurantName.setText(res.getRestaurantName());
+ holder.dateInfo.setText(res.getDate() + " às " + res.getTime());
+ holder.tableInfo.setText("Mesa " + res.getTableNumber() + " • " + res.getGuests() + " pessoas");
+ holder.statusChip.setText(res.getStatus());
+
+ holder.btnCancel.setOnClickListener(v -> listener.onCancel(res));
+ holder.itemView.setOnClickListener(v -> listener.onEdit(res));
+ }
+
+ @Override
+ public int getItemCount() {
+ return reservations.size();
+ }
+
+ static class ViewHolder extends RecyclerView.ViewHolder {
+ TextView restaurantName, dateInfo, tableInfo;
+ Chip statusChip;
+ MaterialButton btnCancel;
+
+ ViewHolder(View itemView) {
+ super(itemView);
+ restaurantName = itemView.findViewById(R.id.txtRestauranteNome);
+ dateInfo = itemView.findViewById(R.id.txtDataHora);
+ tableInfo = itemView.findViewById(R.id.txtMesaPessoas);
+ statusChip = itemView.findViewById(R.id.chipStatus);
+ btnCancel = itemView.findViewById(R.id.btnCancelar);
+ }
+ }
+}
diff --git a/app/src/main/java/com/example/pap_teste/MainActivity.java b/app/src/main/java/com/example/pap_teste/MainActivity.java
index 5573556..c17e7a1 100644
--- a/app/src/main/java/com/example/pap_teste/MainActivity.java
+++ b/app/src/main/java/com/example/pap_teste/MainActivity.java
@@ -35,7 +35,8 @@ public class MainActivity extends AppCompatActivity {
// Check if user is already logged in
if (mAuth.getCurrentUser() != null) {
- startActivity(new Intent(this, ClientDashboardActivity.class));
+ android.app.ActivityOptions options = android.app.ActivityOptions.makeCustomAnimation(this, android.R.anim.fade_in, android.R.anim.fade_out);
+ startActivity(new Intent(this, ClientDashboardActivity.class), options.toBundle());
finish();
return;
}
@@ -101,7 +102,8 @@ public class MainActivity extends AppCompatActivity {
User newUser = new User(uid, name, email, "CLIENTE");
db.collection("users").document(uid).set(newUser)
.addOnSuccessListener(aVoid -> {
- startActivity(new Intent(this, ClientDashboardActivity.class));
+ android.app.ActivityOptions options = android.app.ActivityOptions.makeCustomAnimation(this, android.R.anim.fade_in, android.R.anim.fade_out);
+ startActivity(new Intent(this, ClientDashboardActivity.class), options.toBundle());
finish();
});
})
diff --git a/app/src/main/java/com/example/pap_teste/MyReservationsFragment.java b/app/src/main/java/com/example/pap_teste/MyReservationsFragment.java
index 8a5c5f2..01dedbb 100644
--- a/app/src/main/java/com/example/pap_teste/MyReservationsFragment.java
+++ b/app/src/main/java/com/example/pap_teste/MyReservationsFragment.java
@@ -9,23 +9,22 @@ import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
+import androidx.lifecycle.ViewModelProvider;
+import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
-import com.example.pap_teste.models.Reserva;
-import com.google.firebase.auth.FirebaseAuth;
-import com.google.firebase.firestore.FirebaseFirestore;
-import com.google.firebase.firestore.Query;
-import com.google.firebase.firestore.QueryDocumentSnapshot;
+import com.example.pap_teste.models.LocalReservation;
+import com.example.pap_teste.viewmodels.ReservationViewModel;
import java.util.ArrayList;
import java.util.List;
public class MyReservationsFragment extends Fragment {
private RecyclerView rvReservations;
- private ReservaAdapter adapter;
- private List reservationList = new ArrayList<>();
+ private LocalReservaAdapter adapter;
+ private List reservationList = new ArrayList<>();
private ProgressBar progressBar;
private View emptyState;
- private FirebaseFirestore db;
+ private ReservationViewModel viewModel;
@Nullable
@Override
@@ -36,63 +35,41 @@ public class MyReservationsFragment extends Fragment {
progressBar = view.findViewById(R.id.progressBar);
emptyState = view.findViewById(R.id.emptyState);
- db = FirebaseFirestore.getInstance();
+ viewModel = new ViewModelProvider(this).get(ReservationViewModel.class);
setupAdapter();
- loadReservations();
+ observeReservations();
return view;
}
private void setupAdapter() {
- adapter = new ReservaAdapter(reservationList, new ReservaAdapter.OnReservaActionListener() {
+ adapter = new LocalReservaAdapter(reservationList, new LocalReservaAdapter.OnActionListener() {
@Override
- public void onCheckIn(Reserva reserva) {
- // Implement check-in logic if needed
- Toast.makeText(getContext(), "Check-in disponível em breve.", Toast.LENGTH_SHORT).show();
+ public void onCancel(LocalReservation reservation) {
+ reservation.setStatus("CANCELADA");
+ viewModel.update(reservation);
+ Toast.makeText(getContext(), "Reserva cancelada.", Toast.LENGTH_SHORT).show();
}
@Override
- public void onCancel(Reserva reserva) {
- cancelReservation(reserva);
+ public void onEdit(LocalReservation reservation) {
+ // Show details or edit
+ Toast.makeText(getContext(), "Detalhes: " + reservation.getNotes(), Toast.LENGTH_LONG).show();
}
});
+ rvReservations.setLayoutManager(new LinearLayoutManager(getContext()));
rvReservations.setAdapter(adapter);
}
- private void loadReservations() {
- String userId = FirebaseAuth.getInstance().getUid();
- if (userId == null) return;
-
+ private void observeReservations() {
progressBar.setVisibility(View.VISIBLE);
- db.collection("reservations")
- .whereEqualTo("userId", userId)
- .orderBy("date", Query.Direction.DESCENDING)
- .get()
- .addOnCompleteListener(task -> {
- progressBar.setVisibility(View.GONE);
- if (task.isSuccessful()) {
- reservationList.clear();
- for (QueryDocumentSnapshot document : task.getResult()) {
- Reserva r = document.toObject(Reserva.class);
- r.setId(document.getId());
- reservationList.add(r);
- }
- adapter.notifyDataSetChanged();
- emptyState.setVisibility(reservationList.isEmpty() ? View.VISIBLE : View.GONE);
- } else {
- Toast.makeText(getContext(), "Erro ao carregar reservas.", Toast.LENGTH_SHORT).show();
- }
- });
- }
-
- private void cancelReservation(Reserva reserva) {
- db.collection("reservations").document(reserva.getId())
- .update("status", "cancelled")
- .addOnSuccessListener(aVoid -> {
- Toast.makeText(getContext(), "Reserva cancelada.", Toast.LENGTH_SHORT).show();
- loadReservations();
- })
- .addOnFailureListener(e -> Toast.makeText(getContext(), "Erro ao cancelar.", Toast.LENGTH_SHORT).show());
+ viewModel.getAllReservations().observe(getViewLifecycleOwner(), reservations -> {
+ progressBar.setVisibility(View.GONE);
+ reservationList.clear();
+ reservationList.addAll(reservations);
+ adapter.notifyDataSetChanged();
+ emptyState.setVisibility(reservationList.isEmpty() ? View.VISIBLE : View.GONE);
+ });
}
}
diff --git a/app/src/main/java/com/example/pap_teste/NovaReservaActivity.java b/app/src/main/java/com/example/pap_teste/NovaReservaActivity.java
index 52edcf7..4b8d5dc 100644
--- a/app/src/main/java/com/example/pap_teste/NovaReservaActivity.java
+++ b/app/src/main/java/com/example/pap_teste/NovaReservaActivity.java
@@ -1,333 +1,261 @@
package com.example.pap_teste;
+import android.app.DatePickerDialog;
+import android.app.TimePickerDialog;
import android.os.Bundle;
-import androidx.recyclerview.widget.RecyclerView;
-
+import android.view.View;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+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 android.widget.Button;
+import androidx.lifecycle.ViewModelProvider;
+import androidx.recyclerview.widget.GridLayoutManager;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+import com.example.pap_teste.models.FoodCategory;
+import com.example.pap_teste.models.LocalReservation;
+import com.example.pap_teste.models.Mesa;
+import com.example.pap_teste.models.Restaurant;
+import com.example.pap_teste.viewmodels.ReservationViewModel;
+import com.google.firebase.auth.FirebaseAuth;
+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.Calendar;
+import java.util.List;
+import java.util.Locale;
public class NovaReservaActivity extends AppCompatActivity {
- private enum State {
- CATEGORIES, RESTAURANTS, DETAILS
- }
+ private enum State { CATEGORIES, RESTAURANTS, DETAILS }
private State currentState = State.CATEGORIES;
private String selectedCategory = null;
- private com.example.pap_teste.models.Restaurant selectedRestaurant = null;
+ private Restaurant selectedRestaurant = null;
+ private Mesa selectedMesa = null;
+ private String selectedDate = null;
+ private String selectedTime = null;
- private androidx.recyclerview.widget.RecyclerView rvCategories, rvRestaurants;
- private android.view.View scrollNovaReserva;
- private android.widget.TextView txtTitle;
- private android.widget.ProgressBar progressBar;
+ private RecyclerView rvCategories, rvRestaurants, rvTables;
+ private View scrollNovaReserva;
+ private TextView txtTitle;
+ private ProgressBar progressBar;
+ private ReservationViewModel viewModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EdgeToEdge.enable(this);
setContentView(R.layout.activity_nova_reserva);
+
+ viewModel = new ViewModelProvider(this).get(ReservationViewModel.class);
+
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.novaReservaRoot), (v, insets) -> {
Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
return insets;
});
+ initViews();
+ setupCategories();
+ updateViewState();
+ }
+
+ private void initViews() {
rvCategories = findViewById(R.id.rvCategories);
rvRestaurants = findViewById(R.id.rvRestaurants);
+ rvTables = findViewById(R.id.rvTables);
scrollNovaReserva = findViewById(R.id.scrollNovaReserva);
txtTitle = findViewById(R.id.txtTituloNovaReserva);
progressBar = findViewById(R.id.progressBar);
- Button back = findViewById(R.id.btnVoltar);
- if (back != null) {
- back.setOnClickListener(v -> handleBackNavigation());
- }
-
- setupCategories();
- updateViewState();
+ findViewById(R.id.btnVoltar).setOnClickListener(v -> handleBackNavigation());
+ findViewById(R.id.btnSelectDate).setOnClickListener(v -> showDatePicker());
+ findViewById(R.id.btnSelectTime).setOnClickListener(v -> showTimePicker());
+ findViewById(R.id.btnConfirmarReserva).setOnClickListener(v -> validateAndSave());
}
private void handleBackNavigation() {
if (currentState == State.RESTAURANTS) {
currentState = State.CATEGORIES;
- updateViewState();
} else if (currentState == State.DETAILS) {
currentState = State.RESTAURANTS;
- updateViewState();
} else {
finish();
+ return;
}
+ updateViewState();
}
private void updateViewState() {
- rvCategories
- .setVisibility(currentState == State.CATEGORIES ? android.view.View.VISIBLE : android.view.View.GONE);
- rvRestaurants
- .setVisibility(currentState == State.RESTAURANTS ? android.view.View.VISIBLE : android.view.View.GONE);
- scrollNovaReserva
- .setVisibility(currentState == State.DETAILS ? android.view.View.VISIBLE : android.view.View.GONE);
+ rvCategories.setVisibility(currentState == State.CATEGORIES ? View.VISIBLE : View.GONE);
+ rvRestaurants.setVisibility(currentState == State.RESTAURANTS ? View.VISIBLE : View.GONE);
+ scrollNovaReserva.setVisibility(currentState == State.DETAILS ? View.VISIBLE : View.GONE);
- if (currentState == State.CATEGORIES) {
- txtTitle.setText("Escolha o tema");
- } else if (currentState == State.RESTAURANTS) {
- txtTitle.setText("Restaurantes: " + selectedCategory);
- } else {
- txtTitle.setText("Reserva: " + (selectedRestaurant != null ? selectedRestaurant.getName() : ""));
- setupReservationOptions();
+ switch (currentState) {
+ case CATEGORIES: txtTitle.setText("Escolha o tema"); break;
+ case RESTAURANTS: txtTitle.setText("Restaurantes: " + selectedCategory); break;
+ case DETAILS: txtTitle.setText("Reserva: " + (selectedRestaurant != null ? selectedRestaurant.getName() : "")); break;
}
}
private void setupCategories() {
- java.util.List cats = new java.util.ArrayList<>();
- cats.add(new com.example.pap_teste.models.FoodCategory("Carnes", R.drawable.cat_carnes));
- cats.add(new com.example.pap_teste.models.FoodCategory("Massas", R.drawable.cat_massas));
- cats.add(new com.example.pap_teste.models.FoodCategory("Sushi", R.drawable.cat_sushi));
- cats.add(new com.example.pap_teste.models.FoodCategory("Pizzas", R.drawable.cat_pizzas));
- cats.add(new com.example.pap_teste.models.FoodCategory("Sobremesas", R.drawable.cat_sobremesas));
+ List cats = new ArrayList<>();
+ cats.add(new FoodCategory("Carnes", R.drawable.cat_carnes));
+ cats.add(new FoodCategory("Massas", R.drawable.cat_massas));
+ cats.add(new FoodCategory("Sushi", R.drawable.cat_sushi));
+ cats.add(new FoodCategory("Pizzas", R.drawable.cat_pizzas));
+ cats.add(new FoodCategory("Sobremesas", R.drawable.cat_sobremesas));
- rvCategories.setLayoutManager(new androidx.recyclerview.widget.LinearLayoutManager(this));
+ rvCategories.setLayoutManager(new LinearLayoutManager(this));
rvCategories.setAdapter(new FoodCategoryAdapter(cats, category -> {
selectedCategory = category.getName();
currentState = State.RESTAURANTS;
- setupRestaurants();
+ loadRestaurants();
updateViewState();
}));
}
- private void setupRestaurants() {
- java.util.List filteredList = new java.util.ArrayList<>();
- com.google.firebase.database.DatabaseReference usersRef = com.google.firebase.database.FirebaseDatabase
- .getInstance().getReference("Restaurantes");
-
- if (progressBar != null)
- progressBar.setVisibility(android.view.View.VISIBLE);
-
- usersRef.orderByChild("category").equalTo(selectedCategory)
- .addListenerForSingleValueEvent(new com.google.firebase.database.ValueEventListener() {
- @Override
- public void onDataChange(
- @androidx.annotation.NonNull com.google.firebase.database.DataSnapshot snapshot) {
- if (progressBar != null)
- progressBar.setVisibility(android.view.View.GONE);
- filteredList.clear();
- for (com.google.firebase.database.DataSnapshot ds : snapshot.getChildren()) {
- String role = ds.child("role").getValue(String.class);
- String accountType = ds.child("accountType").getValue(String.class);
-
- if ("ADMIN".equalsIgnoreCase(role) || "ESTABELECIMENTO".equalsIgnoreCase(accountType)) {
- String name = ds.child("establishmentName").getValue(String.class);
- if (name == null)
- name = ds.child("displayName").getValue(String.class);
- String email = ds.child("email").getValue(String.class);
- String cat = ds.child("category").getValue(String.class);
- String logoUrl = ds.child("logoUrl").getValue(String.class);
-
- if (name != null && email != null) {
- filteredList.add(new com.example.pap_teste.models.Restaurant(name, cat, email,
- false, logoUrl));
- }
- }
- }
-
- rvRestaurants.setLayoutManager(
- new androidx.recyclerview.widget.LinearLayoutManager(NovaReservaActivity.this));
- rvRestaurants.setAdapter(new RestaurantAdapter(filteredList, restaurant -> {
- selectedRestaurant = restaurant;
- currentState = State.DETAILS;
- updateViewState();
- }));
+ private void loadRestaurants() {
+ progressBar.setVisibility(View.VISIBLE);
+ DatabaseReference ref = FirebaseDatabase.getInstance().getReference("Restaurantes");
+ ref.orderByChild("category").equalTo(selectedCategory).addListenerForSingleValueEvent(new ValueEventListener() {
+ @Override
+ public void onDataChange(@NonNull DataSnapshot snapshot) {
+ progressBar.setVisibility(View.GONE);
+ List list = new ArrayList<>();
+ for (DataSnapshot ds : snapshot.getChildren()) {
+ String name = ds.child("establishmentName").getValue(String.class);
+ if (name == null) name = ds.child("displayName").getValue(String.class);
+ String email = ds.child("email").getValue(String.class);
+ String cat = ds.child("category").getValue(String.class);
+ String logo = ds.child("logoUrl").getValue(String.class);
+ if (name != null && email != null) {
+ list.add(new Restaurant(name, cat, email, false, logo));
}
+ }
+ rvRestaurants.setLayoutManager(new LinearLayoutManager(NovaReservaActivity.this));
+ rvRestaurants.setAdapter(new RestaurantAdapter(list, restaurant -> {
+ selectedRestaurant = restaurant;
+ currentState = State.DETAILS;
+ loadTables();
+ updateViewState();
+ }));
+ }
- @Override
- public void onCancelled(
- @androidx.annotation.NonNull com.google.firebase.database.DatabaseError error) {
- if (progressBar != null)
- progressBar.setVisibility(android.view.View.GONE);
- android.widget.Toast.makeText(NovaReservaActivity.this, "Erro ao carregar restaurantes.",
- android.widget.Toast.LENGTH_SHORT).show();
- }
- });
+ @Override
+ public void onCancelled(@NonNull DatabaseError error) {
+ progressBar.setVisibility(View.GONE);
+ Toast.makeText(NovaReservaActivity.this, "Erro ao carregar.", Toast.LENGTH_SHORT).show();
+ }
+ });
}
- private String selectedDate = null;
- private String selectedTime = null;
+ private void loadTables() {
+ progressBar.setVisibility(View.VISIBLE);
+ DatabaseReference ref = FirebaseDatabase.getInstance().getReference("Mesas");
+ ref.addListenerForSingleValueEvent(new ValueEventListener() {
+ @Override
+ public void onDataChange(@NonNull DataSnapshot snapshot) {
+ progressBar.setVisibility(View.GONE);
+ List tables = new ArrayList<>();
+ for (DataSnapshot ds : snapshot.getChildren()) {
+ Mesa m = ds.getValue(Mesa.class);
+ if (m != null && selectedRestaurant.getEmail().equalsIgnoreCase(m.getRestauranteEmail())) {
+ tables.add(m);
+ }
+ }
+ rvTables.setLayoutManager(new GridLayoutManager(NovaReservaActivity.this, 3));
+ rvTables.setAdapter(new TableSelectionAdapter(tables, mesa -> selectedMesa = mesa));
+ }
- private void setupReservationOptions() {
- android.widget.Button btnDate = findViewById(R.id.btnSelectDate);
- android.widget.Button btnTime = findViewById(R.id.btnSelectTime);
-
- btnDate.setOnClickListener(v -> {
- java.util.Calendar cal = java.util.Calendar.getInstance();
- new android.app.DatePickerDialog(this, (view, year, month, dayOfMonth) -> {
- selectedDate = dayOfMonth + "/" + (month + 1) + "/" + year;
- btnDate.setText(selectedDate);
- }, cal.get(java.util.Calendar.YEAR), cal.get(java.util.Calendar.MONTH),
- cal.get(java.util.Calendar.DAY_OF_MONTH)).show();
+ @Override
+ public void onCancelled(@NonNull DatabaseError error) {
+ progressBar.setVisibility(View.GONE);
+ }
});
-
- btnTime.setOnClickListener(v -> {
- java.util.Calendar cal = java.util.Calendar.getInstance();
- new android.app.TimePickerDialog(this, (view, hourOfDay, minute) -> {
- selectedTime = String.format(java.util.Locale.getDefault(), "%02d:%02d", hourOfDay, minute);
- btnTime.setText(selectedTime);
- }, cal.get(java.util.Calendar.HOUR_OF_DAY), cal.get(java.util.Calendar.MINUTE), true).show();
- });
-
- findViewById(R.id.btnConfirmarReserva).setOnClickListener(v -> saveReservation());
}
- private void saveReservation() {
- android.widget.EditText etPartySize = findViewById(R.id.etPartySize);
- int val = 0;
- try {
- val = Integer.parseInt(etPartySize.getText().toString());
- } catch (Exception e) {
- }
- final int partySize = val;
+ private void showDatePicker() {
+ Calendar cal = Calendar.getInstance();
+ new DatePickerDialog(this, (view, year, month, day) -> {
+ selectedDate = String.format(Locale.getDefault(), "%02d/%02d/%d", day, month + 1, year);
+ ((Button)findViewById(R.id.btnSelectDate)).setText(selectedDate);
+ }, cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH)).show();
+ }
- if (selectedDate == null || selectedTime == null || partySize == 0) {
- android.widget.Toast.makeText(this, "Por favor, selecione data, hora e número de pessoas.",
- android.widget.Toast.LENGTH_SHORT).show();
+ private void showTimePicker() {
+ Calendar cal = Calendar.getInstance();
+ new TimePickerDialog(this, (view, hour, min) -> {
+ selectedTime = String.format(Locale.getDefault(), "%02d:%02d", hour, min);
+ ((Button)findViewById(R.id.btnSelectTime)).setText(selectedTime);
+ }, cal.get(Calendar.HOUR_OF_DAY), cal.get(Calendar.MINUTE), true).show();
+ }
+
+ private void validateAndSave() {
+ EditText etPartySize = findViewById(R.id.etPartySize);
+ EditText etNotes = findViewById(R.id.etNotes);
+ String partySizeStr = etPartySize.getText().toString();
+
+ if (selectedDate == null || selectedTime == null || selectedMesa == null || partySizeStr.isEmpty()) {
+ Toast.makeText(this, "Preencha todos os campos e escolha a mesa.", Toast.LENGTH_SHORT).show();
return;
}
- String restEmail = selectedRestaurant.getEmail();
+ int partySize = Integer.parseInt(partySizeStr);
+ if (partySize > selectedMesa.getCapacidade()) {
+ Toast.makeText(this, "A mesa escolhida só suporta " + selectedMesa.getCapacidade() + " pessoas.", Toast.LENGTH_SHORT).show();
+ return;
+ }
- if (progressBar != null)
- progressBar.setVisibility(android.view.View.VISIBLE);
- android.widget.Button btnConfirmar = findViewById(R.id.btnConfirmarReserva);
- if (btnConfirmar != null)
- btnConfirmar.setEnabled(false);
-
- com.google.firebase.database.DatabaseReference mesasRef = com.google.firebase.database.FirebaseDatabase
- .getInstance().getReference("Mesas");
-
- mesasRef.addListenerForSingleValueEvent(new com.google.firebase.database.ValueEventListener() {
- @Override
- public void onDataChange(@androidx.annotation.NonNull com.google.firebase.database.DataSnapshot snapshot) {
- int totalMesas = 0;
- 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.getRestauranteEmail() != null && restEmail.trim().equalsIgnoreCase(m.getRestauranteEmail().trim())) {
- totalMesas++;
- }
+ // Conflict check
+ viewModel.checkConflict(selectedDate, selectedMesa.getNumero(), isAvailable -> {
+ runOnUiThread(() -> {
+ if (isAvailable) {
+ saveToFirebaseAndRoom(partySize, etNotes.getText().toString());
+ } else {
+ Toast.makeText(this, "Esta mesa já está reservada para este dia.", Toast.LENGTH_LONG).show();
}
-
- if (totalMesas == 0) {
- proceedWithReservation(partySize);
- return;
- }
-
- checkReservationsAndSave(totalMesas, partySize);
- }
-
- @Override
- public void onCancelled(@androidx.annotation.NonNull com.google.firebase.database.DatabaseError error) {
- proceedWithReservation(partySize);
- }
+ });
});
}
- private void checkReservationsAndSave(int totalMesas, final int partySize) {
- String restEmail = selectedRestaurant.getEmail();
- com.google.firebase.database.DatabaseReference reservasRef = com.google.firebase.database.FirebaseDatabase
- .getInstance().getReference("reservas");
-
- reservasRef.addListenerForSingleValueEvent(new com.google.firebase.database.ValueEventListener() {
- @Override
- public void onDataChange(
- @androidx.annotation.NonNull com.google.firebase.database.DataSnapshot snapshot) {
- int ocupadas = 0;
- java.util.Map ocupacaoPorHora = new java.util.HashMap<>();
-
- for (com.google.firebase.database.DataSnapshot ds : snapshot.getChildren()) {
- com.example.pap_teste.models.Reserva r = ds
- .getValue(com.example.pap_teste.models.Reserva.class);
- if (r != null && r.getRestauranteEmail() != null &&
- r.getRestauranteEmail().trim().equalsIgnoreCase(restEmail.trim()) &&
- selectedDate.equals(r.getData()) && !"Cancelada".equals(r.getEstado())
- && !"Recusada".equals(r.getEstado())) {
- int count = ocupacaoPorHora.getOrDefault(r.getHora(), 0) + 1;
- ocupacaoPorHora.put(r.getHora(), count);
- if (selectedTime.equals(r.getHora())) {
- ocupadas++;
- }
- }
- }
-
- if (ocupadas >= totalMesas) {
- String sugestao = "";
- String[] horasComuns = { "12:00", "12:30", "13:00", "13:30", "14:00", "19:00", "19:30",
- "20:00", "20:30", "21:00", "21:30", "22:00" };
- for (String h : horasComuns) {
- if (ocupacaoPorHora.getOrDefault(h, 0) < totalMesas && !h.equals(selectedTime)) {
- sugestao = h;
- break; // Encontramos a primeira sugestão livre
- }
- }
- String msg = "Não há mesas disponíveis para as " + selectedTime + ".";
- if (!sugestao.isEmpty()) {
- msg += " Sugestão: tente reservar para as " + sugestao + ".";
- } else {
- msg += " Tente para outro dia.";
- }
- android.widget.Toast
- .makeText(NovaReservaActivity.this, msg, android.widget.Toast.LENGTH_LONG).show();
- } else {
- proceedWithReservation(partySize);
- }
- }
-
- @Override
- public void onCancelled(
- @androidx.annotation.NonNull com.google.firebase.database.DatabaseError error) {
- proceedWithReservation(partySize);
- }
- });
- }
-
- private void proceedWithReservation(int partySize) {
- String userEmail = com.google.firebase.auth.FirebaseAuth.getInstance().getCurrentUser() != null
- ? com.google.firebase.auth.FirebaseAuth.getInstance().getCurrentUser().getEmail()
- : "cliente@teste.com";
- com.google.firebase.database.DatabaseReference ref = com.google.firebase.database.FirebaseDatabase.getInstance()
- .getReference("reservas");
+ private void saveToFirebaseAndRoom(int guests, String notes) {
+ progressBar.setVisibility(View.VISIBLE);
+ DatabaseReference ref = FirebaseDatabase.getInstance().getReference("reservas");
String id = ref.push().getKey();
+ String userEmail = FirebaseAuth.getInstance().getCurrentUser() != null ? FirebaseAuth.getInstance().getCurrentUser().getEmail() : "anon@test.com";
- com.example.pap_teste.models.Reserva reserva = new com.example.pap_teste.models.Reserva(
- id,
- userEmail,
- selectedRestaurant.getName(),
- selectedRestaurant.getEmail(),
- selectedDate,
- selectedTime,
- partySize,
- "Pendente");
+ LocalReservation local = new LocalReservation();
+ local.setFirebaseId(id);
+ local.setRestaurantName(selectedRestaurant.getName());
+ local.setRestaurantEmail(selectedRestaurant.getEmail());
+ local.setDate(selectedDate);
+ local.setTime(selectedTime);
+ local.setGuests(guests);
+ local.setTableNumber(selectedMesa.getNumero());
+ local.setNotes(notes);
+ local.setStatus("PENDENTE");
if (id != null) {
- ref.child(id).setValue(reserva).addOnCompleteListener(task -> {
- if (progressBar != null)
- progressBar.setVisibility(android.view.View.GONE);
- android.widget.Button btnConfirmar = findViewById(R.id.btnConfirmarReserva);
- if (btnConfirmar != null)
- btnConfirmar.setEnabled(true);
-
+ ref.child(id).setValue(local).addOnCompleteListener(task -> {
+ progressBar.setVisibility(View.GONE);
if (task.isSuccessful()) {
- android.widget.Toast
- .makeText(NovaReservaActivity.this, "Reserva solicitada com sucesso!",
- android.widget.Toast.LENGTH_SHORT)
- .show();
+ viewModel.insert(local);
+ Toast.makeText(this, "Reserva realizada com sucesso!", Toast.LENGTH_LONG).show();
finish();
} else {
- android.widget.Toast
- .makeText(NovaReservaActivity.this, "Erro ao salvar reserva.",
- android.widget.Toast.LENGTH_SHORT)
- .show();
+ Toast.makeText(this, "Erro ao guardar no servidor.", Toast.LENGTH_SHORT).show();
}
});
}
diff --git a/app/src/main/java/com/example/pap_teste/OnboardingActivity.java b/app/src/main/java/com/example/pap_teste/OnboardingActivity.java
index 387401c..9ce7229 100644
--- a/app/src/main/java/com/example/pap_teste/OnboardingActivity.java
+++ b/app/src/main/java/com/example/pap_teste/OnboardingActivity.java
@@ -39,7 +39,8 @@ public class OnboardingActivity extends AppCompatActivity {
tagline.startAnimation(fadeIn);
btnGetStarted.setOnClickListener(v -> {
- startActivity(new Intent(OnboardingActivity.this, MainActivity.class));
+ android.app.ActivityOptions options = android.app.ActivityOptions.makeCustomAnimation(this, android.R.anim.fade_in, android.R.anim.fade_out);
+ startActivity(new Intent(OnboardingActivity.this, MainActivity.class), options.toBundle());
finish();
});
}
diff --git a/app/src/main/java/com/example/pap_teste/ProfileFragment.java b/app/src/main/java/com/example/pap_teste/ProfileFragment.java
index 7a4ee69..cbd415a 100644
--- a/app/src/main/java/com/example/pap_teste/ProfileFragment.java
+++ b/app/src/main/java/com/example/pap_teste/ProfileFragment.java
@@ -10,6 +10,7 @@ import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
+import android.widget.Toast;
import com.bumptech.glide.Glide;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;
diff --git a/app/src/main/java/com/example/pap_teste/SplashActivity.java b/app/src/main/java/com/example/pap_teste/SplashActivity.java
new file mode 100644
index 0000000..4c79594
--- /dev/null
+++ b/app/src/main/java/com/example/pap_teste/SplashActivity.java
@@ -0,0 +1,36 @@
+package com.example.pap_teste;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.view.animation.Animation;
+import android.view.animation.AnimationUtils;
+import android.widget.ImageView;
+import android.widget.TextView;
+import androidx.appcompat.app.AppCompatActivity;
+
+public class SplashActivity extends AppCompatActivity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_splash);
+
+ ImageView logo = findViewById(R.id.splash_logo);
+ TextView title = findViewById(R.id.splash_title);
+ TextView subtitle = findViewById(R.id.splash_subtitle);
+
+ Animation fadeIn = AnimationUtils.loadAnimation(this, android.R.anim.fade_in);
+ fadeIn.setDuration(1500);
+
+ logo.startAnimation(fadeIn);
+ title.startAnimation(fadeIn);
+ subtitle.startAnimation(fadeIn);
+
+ new Handler(Looper.getMainLooper()).postDelayed(() -> {
+ startActivity(new Intent(SplashActivity.this, OnboardingActivity.class));
+ finish();
+ }, 2500);
+ }
+}
diff --git a/app/src/main/java/com/example/pap_teste/TableSelectionAdapter.java b/app/src/main/java/com/example/pap_teste/TableSelectionAdapter.java
new file mode 100644
index 0000000..98edb54
--- /dev/null
+++ b/app/src/main/java/com/example/pap_teste/TableSelectionAdapter.java
@@ -0,0 +1,87 @@
+package com.example.pap_teste;
+
+import android.graphics.Color;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+import com.example.pap_teste.models.Mesa;
+import com.google.android.material.card.MaterialCardView;
+import java.util.List;
+
+public class TableSelectionAdapter extends RecyclerView.Adapter {
+
+ private final List tables;
+ private final OnTableClickListener listener;
+ private int selectedPosition = -1;
+
+ public interface OnTableClickListener {
+ void onTableClick(Mesa mesa);
+ }
+
+ public TableSelectionAdapter(List tables, OnTableClickListener listener) {
+ this.tables = tables;
+ this.listener = listener;
+ }
+
+ @NonNull
+ @Override
+ public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_table, parent, false);
+ return new ViewHolder(view);
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
+ Mesa mesa = tables.get(position);
+ holder.txtNumber.setText("Mesa " + mesa.getNumero());
+
+ boolean isOccupied = "OCUPADA".equalsIgnoreCase(mesa.getEstado()) || "RESERVADA".equalsIgnoreCase(mesa.getEstado());
+ holder.txtStatus.setText(mesa.getEstado());
+
+ if (isOccupied) {
+ holder.card.setCardBackgroundColor(Color.parseColor("#F5F5F5"));
+ holder.card.setStrokeColor(Color.TRANSPARENT);
+ holder.txtStatus.setTextColor(Color.GRAY);
+ holder.itemView.setEnabled(false);
+ holder.imgStatus.setAlpha(0.3f);
+ } else {
+ boolean isSelected = selectedPosition == position;
+ holder.card.setCardBackgroundColor(isSelected ? holder.itemView.getContext().getColor(R.color.colorChipConfirmed) : Color.WHITE);
+ holder.card.setStrokeColor(isSelected ? holder.itemView.getContext().getColor(R.color.colorSuccess) : holder.itemView.getContext().getColor(R.color.colorBorder));
+ holder.txtStatus.setTextColor(isSelected ? holder.itemView.getContext().getColor(R.color.colorSuccess) : holder.itemView.getContext().getColor(R.color.colorTextSecondary));
+ holder.itemView.setEnabled(true);
+ holder.imgStatus.setAlpha(1.0f);
+ }
+
+ holder.itemView.setOnClickListener(v -> {
+ int previousSelected = selectedPosition;
+ selectedPosition = holder.getAdapterPosition();
+ if (previousSelected != -1) notifyItemChanged(previousSelected);
+ notifyItemChanged(selectedPosition);
+ listener.onTableClick(mesa);
+ });
+ }
+
+ @Override
+ public int getItemCount() {
+ return tables.size();
+ }
+
+ static class ViewHolder extends RecyclerView.ViewHolder {
+ MaterialCardView card;
+ TextView txtNumber, txtStatus;
+ ImageView imgStatus;
+
+ ViewHolder(View itemView) {
+ super(itemView);
+ card = itemView.findViewById(R.id.cardTable);
+ txtNumber = itemView.findViewById(R.id.txtTableNumber);
+ txtStatus = itemView.findViewById(R.id.txtTableStatus);
+ imgStatus = itemView.findViewById(R.id.imgTableStatus);
+ }
+ }
+}
diff --git a/app/src/main/java/com/example/pap_teste/data/AppDatabase.java b/app/src/main/java/com/example/pap_teste/data/AppDatabase.java
new file mode 100644
index 0000000..ed12ef8
--- /dev/null
+++ b/app/src/main/java/com/example/pap_teste/data/AppDatabase.java
@@ -0,0 +1,24 @@
+package com.example.pap_teste.data;
+
+import android.content.Context;
+import androidx.room.Database;
+import androidx.room.Room;
+import androidx.room.RoomDatabase;
+import com.example.pap_teste.models.LocalReservation;
+
+@Database(entities = {LocalReservation.class}, version = 1, exportSchema = false)
+public abstract class AppDatabase extends RoomDatabase {
+ private static AppDatabase instance;
+
+ public abstract ReservationDao reservationDao();
+
+ public static synchronized AppDatabase getInstance(Context context) {
+ if (instance == null) {
+ instance = Room.databaseBuilder(context.getApplicationContext(),
+ AppDatabase.class, "namesa_database")
+ .fallbackToDestructiveMigration()
+ .build();
+ }
+ return instance;
+ }
+}
diff --git a/app/src/main/java/com/example/pap_teste/data/ReservationDao.java b/app/src/main/java/com/example/pap_teste/data/ReservationDao.java
new file mode 100644
index 0000000..bfed1b2
--- /dev/null
+++ b/app/src/main/java/com/example/pap_teste/data/ReservationDao.java
@@ -0,0 +1,29 @@
+package com.example.pap_teste.data;
+
+import androidx.lifecycle.LiveData;
+import androidx.room.Dao;
+import androidx.room.Delete;
+import androidx.room.Insert;
+import androidx.room.OnConflictStrategy;
+import androidx.room.Query;
+import androidx.room.Update;
+import com.example.pap_teste.models.LocalReservation;
+import java.util.List;
+
+@Dao
+public interface ReservationDao {
+ @Insert(onConflict = OnConflictStrategy.REPLACE)
+ void insert(LocalReservation reservation);
+
+ @Update
+ void update(LocalReservation reservation);
+
+ @Delete
+ void delete(LocalReservation reservation);
+
+ @Query("SELECT * FROM local_reservations ORDER BY date DESC, time DESC")
+ LiveData> getAllReservations();
+
+ @Query("SELECT * FROM local_reservations WHERE date = :date AND tableNumber = :tableId AND status != 'CANCELLED'")
+ List getReservationsForTable(String date, int tableId);
+}
diff --git a/app/src/main/java/com/example/pap_teste/models/LocalReservation.java b/app/src/main/java/com/example/pap_teste/models/LocalReservation.java
new file mode 100644
index 0000000..880a22a
--- /dev/null
+++ b/app/src/main/java/com/example/pap_teste/models/LocalReservation.java
@@ -0,0 +1,51 @@
+package com.example.pap_teste.models;
+
+import androidx.room.Entity;
+import androidx.room.PrimaryKey;
+
+@Entity(tableName = "local_reservations")
+public class LocalReservation {
+ @PrimaryKey(autoGenerate = true)
+ private int id;
+ private String firebaseId;
+ private String restaurantName;
+ private String restaurantEmail;
+ private String date;
+ private String time;
+ private int guests;
+ private String status;
+ private int tableNumber;
+ private String notes;
+
+ public LocalReservation() {}
+
+ public int getId() { return id; }
+ public void setId(int id) { this.id = id; }
+
+ public String getFirebaseId() { return firebaseId; }
+ public void setFirebaseId(String firebaseId) { this.firebaseId = firebaseId; }
+
+ public String getRestaurantName() { return restaurantName; }
+ public void setRestaurantName(String restaurantName) { this.restaurantName = restaurantName; }
+
+ public String getRestaurantEmail() { return restaurantEmail; }
+ public void setRestaurantEmail(String restaurantEmail) { this.restaurantEmail = restaurantEmail; }
+
+ public String getDate() { return date; }
+ public void setDate(String date) { this.date = date; }
+
+ public String getTime() { return time; }
+ public void setTime(String time) { this.time = time; }
+
+ public int getGuests() { return guests; }
+ public void setGuests(int guests) { this.guests = guests; }
+
+ public String getStatus() { return status; }
+ public void setStatus(String status) { this.status = status; }
+
+ public int getTableNumber() { return tableNumber; }
+ public void setTableNumber(int tableNumber) { this.tableNumber = tableNumber; }
+
+ public String getNotes() { return notes; }
+ public void setNotes(String notes) { this.notes = notes; }
+}
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
index 6f5ab33..d29286b 100644
--- a/app/src/main/java/com/example/pap_teste/models/Reserva.java
+++ b/app/src/main/java/com/example/pap_teste/models/Reserva.java
@@ -1,14 +1,25 @@
package com.example.pap_teste.models;
+import com.google.firebase.Timestamp;
+
public class Reserva {
private String id;
+ private String userId;
+ private String restaurantId;
+ private String restaurantName;
private String clienteEmail;
private String restauranteName;
private String restauranteEmail;
private String data;
private String hora;
private int pessoas;
+ private int guests;
private String estado;
+ private String status;
+ private Timestamp date;
+ private String timeSlot;
+ private String specialRequests;
+ private Timestamp createdAt;
public Reserva() {
}
@@ -25,27 +36,41 @@ public class Reserva {
this.estado = estado;
}
+ // Existing getters/setters
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; }
+
+ // New getters/setters to fix ReservationActivity
+ public String getUserId() { return userId != null ? userId : clienteEmail; }
+ public void setUserId(String userId) { this.userId = userId; }
+ public String getRestaurantId() { return restaurantId != null ? restaurantId : restauranteEmail; }
+ public void setRestaurantId(String restaurantId) { this.restaurantId = restaurantId; }
+ public String getRestaurantName() { return restaurantName != null ? restaurantName : restauranteName; }
+ public void setRestaurantName(String restaurantName) { this.restaurantName = restaurantName; }
+ public int getGuests() { return guests != 0 ? guests : pessoas; }
+ public void setGuests(int guests) { this.guests = guests; }
+ public String getStatus() { return status != null ? status : estado; }
+ public void setStatus(String status) { this.status = status; }
+ public Timestamp getDate() { return date; }
+ public void setDate(Timestamp date) { this.date = date; }
+ public String getTimeSlot() { return timeSlot != null ? timeSlot : hora; }
+ public void setTimeSlot(String timeSlot) { this.timeSlot = timeSlot; }
+ public String getSpecialRequests() { return specialRequests; }
+ public void setSpecialRequests(String specialRequests) { this.specialRequests = specialRequests; }
+ public Timestamp getCreatedAt() { return createdAt; }
+ public void setCreatedAt(Timestamp createdAt) { this.createdAt = createdAt; }
}
diff --git a/app/src/main/java/com/example/pap_teste/viewmodels/ReservationViewModel.java b/app/src/main/java/com/example/pap_teste/viewmodels/ReservationViewModel.java
new file mode 100644
index 0000000..c002c8e
--- /dev/null
+++ b/app/src/main/java/com/example/pap_teste/viewmodels/ReservationViewModel.java
@@ -0,0 +1,53 @@
+package com.example.pap_teste.viewmodels;
+
+import android.app.Application;
+import androidx.annotation.NonNull;
+import androidx.lifecycle.AndroidViewModel;
+import androidx.lifecycle.LiveData;
+import com.example.pap_teste.data.AppDatabase;
+import com.example.pap_teste.data.ReservationDao;
+import com.example.pap_teste.models.LocalReservation;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+public class ReservationViewModel extends AndroidViewModel {
+ private final ReservationDao reservationDao;
+ private final ExecutorService executorService;
+ private final LiveData> allReservations;
+
+ public ReservationViewModel(@NonNull Application application) {
+ super(application);
+ AppDatabase db = AppDatabase.getInstance(application);
+ reservationDao = db.reservationDao();
+ allReservations = reservationDao.getAllReservations();
+ executorService = Executors.newSingleThreadExecutor();
+ }
+
+ public LiveData> getAllReservations() {
+ return allReservations;
+ }
+
+ public void insert(LocalReservation reservation) {
+ executorService.execute(() -> reservationDao.insert(reservation));
+ }
+
+ public void update(LocalReservation reservation) {
+ executorService.execute(() -> reservationDao.update(reservation));
+ }
+
+ public void delete(LocalReservation reservation) {
+ executorService.execute(() -> reservationDao.delete(reservation));
+ }
+
+ public void checkConflict(String date, int tableId, OnConflictCheckListener listener) {
+ executorService.execute(() -> {
+ List conflicts = reservationDao.getReservationsForTable(date, tableId);
+ listener.onResult(conflicts.isEmpty());
+ });
+ }
+
+ public interface OnConflictCheckListener {
+ void onResult(boolean isAvailable);
+ }
+}
diff --git a/app/src/main/res/layout/activity_nova_reserva.xml b/app/src/main/res/layout/activity_nova_reserva.xml
index f665f28..d099154 100644
--- a/app/src/main/res/layout/activity_nova_reserva.xml
+++ b/app/src/main/res/layout/activity_nova_reserva.xml
@@ -161,6 +161,24 @@
android:textColor="@color/colorTextPrimary"
app:strokeColor="@color/colorDivider" />
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_splash.xml b/app/src/main/res/layout/activity_splash.xml
new file mode 100644
index 0000000..3071c49
--- /dev/null
+++ b/app/src/main/res/layout/activity_splash.xml
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/item_reserva_local.xml b/app/src/main/res/layout/item_reserva_local.xml
new file mode 100644
index 0000000..3fe9548
--- /dev/null
+++ b/app/src/main/res/layout/item_reserva_local.xml
@@ -0,0 +1,96 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/item_table.xml b/app/src/main/res/layout/item_table.xml
new file mode 100644
index 0000000..d27aa16
--- /dev/null
+++ b/app/src/main/res/layout/item_table.xml
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 57bf325..8d2cc6d 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -13,6 +13,7 @@ googleServices = "4.4.2"
firebaseDatabase = "22.0.1"
glide = "4.16.0"
firebaseStorage = "21.0.1"
+room = "2.6.1"
[libraries]
junit = { group = "junit", name = "junit", version.ref = "junit" }
@@ -27,6 +28,9 @@ firebase-bom = { group = "com.google.firebase", name = "firebase-bom", version.r
firebase-database = { group = "com.google.firebase", name = "firebase-database", version.ref = "firebaseDatabase" }
glide = { group = "com.github.bumptech.glide", name = "glide", version.ref = "glide" }
firebase-storage = { group = "com.google.firebase", name = "firebase-storage", version.ref = "firebaseStorage" }
+room-runtime = { group = "androidx.room", name = "room-runtime", version.ref = "room" }
+room-compiler = { group = "androidx.room", name = "room-compiler", version.ref = "room" }
+room-ktx = { group = "androidx.room", name = "room-ktx", version.ref = "room" }
[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }