diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index b1b9e33..fa7d6df 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -24,95 +24,32 @@
android:roundIcon="@drawable/na_mesa"
android:supportsRtl="true"
android:theme="@style/Theme.Pap_teste">
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/example/pap_teste/AddStaffActivity.java b/app/src/main/java/com/example/pap_teste/AddStaffActivity.java
deleted file mode 100644
index dba5c09..0000000
--- a/app/src/main/java/com/example/pap_teste/AddStaffActivity.java
+++ /dev/null
@@ -1,135 +0,0 @@
-package com.example.pap_teste;
-
-import android.os.Bundle;
-import android.view.View;
-import android.widget.Button;
-import android.widget.EditText;
-import android.widget.Spinner;
-import android.widget.ArrayAdapter;
-import android.widget.Toast;
-import java.util.ArrayList;
-import android.app.AlertDialog;
-import android.content.DialogInterface;
-import android.text.InputType;
-
-import androidx.activity.EdgeToEdge;
-import androidx.appcompat.app.AppCompatActivity;
-import androidx.core.graphics.Insets;
-import androidx.core.view.ViewCompat;
-import androidx.core.view.WindowInsetsCompat;
-
-import com.example.pap_teste.models.Staff;
-import com.google.firebase.database.DatabaseReference;
-import com.google.firebase.database.FirebaseDatabase;
-
-public class AddStaffActivity extends AppCompatActivity {
-
- private Button addButton;
- private EditText nameEditText;
- private Spinner zonaSpinner;
- private Button btnAddZone;
- private Spinner mesaSpinner;
- private ArrayList zones;
- private ArrayList mesas;
- private ArrayAdapter adapter;
- private ArrayAdapter mesaAdapter;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- EdgeToEdge.enable(this);
- setContentView(R.layout.activity_add_staff);
- ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
- Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
- v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
- return insets;
- });
-
- addButton = findViewById(R.id.addButton);
- nameEditText = findViewById(R.id.nammeEditText);
- zonaSpinner = findViewById(R.id.zonaSpinner);
- btnAddZone = findViewById(R.id.btnAddZone);
- mesaSpinner = findViewById(R.id.mesaSpinner);
-
- Button btnVoltarAddStaff = findViewById(R.id.btnVoltarAddStaff);
- if (btnVoltarAddStaff != null) {
- btnVoltarAddStaff.setOnClickListener(v -> finish());
- }
-
- zones = new ArrayList<>();
- zones.add("Sala");
- zones.add("Esplanada");
- zones.add("Balcão");
-
- adapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, zones);
- adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
- zonaSpinner.setAdapter(adapter);
-
- mesas = new ArrayList<>();
- for (int i = 1; i <= 10; i++) {
- mesas.add("Mesa " + i);
- }
- mesaAdapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, mesas);
- mesaAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
- mesaSpinner.setAdapter(mesaAdapter);
-
- btnAddZone.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- AlertDialog.Builder builder = new AlertDialog.Builder(AddStaffActivity.this);
- builder.setTitle("Adicionar Zona");
-
- final EditText input = new EditText(AddStaffActivity.this);
- input.setInputType(InputType.TYPE_CLASS_TEXT);
- builder.setView(input);
-
- builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- String newZone = input.getText().toString();
- if (!newZone.isEmpty()) {
- zones.add(newZone);
- adapter.notifyDataSetChanged();
- zonaSpinner.setSelection(zones.size() - 1);
- }
- }
- });
- builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- dialog.cancel();
- }
- });
-
- builder.show();
- }
- });
-
- addButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- String name = nameEditText.getText().toString();
- String zona = "";
- if (zonaSpinner.getSelectedItem() != null) {
- zona = zonaSpinner.getSelectedItem().toString();
- }
- String mesa = "";
- if (mesaSpinner.getSelectedItem() != null) {
- mesa = mesaSpinner.getSelectedItem().toString();
- }
-
- if (!name.isEmpty()) {
- DatabaseReference databaseReference = FirebaseDatabase.getInstance().getReference("Staff");
- String uuid = java.util.UUID.randomUUID().toString();
- Staff staff = new Staff(name, zona, mesa, uuid);
- databaseReference.child(uuid).setValue(staff);
-
- Toast.makeText(AddStaffActivity.this, "Staff adicionado com sucesso!", Toast.LENGTH_SHORT).show();
- finish();
- } else {
- Toast.makeText(AddStaffActivity.this, "Erro: Preencha todos os campos", Toast.LENGTH_SHORT).show();
- }
- }
- });
- }
-}
\ No newline at end of file
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 4e42ca2..ab6d6e7 100644
--- a/app/src/main/java/com/example/pap_teste/ClientDashboardActivity.java
+++ b/app/src/main/java/com/example/pap_teste/ClientDashboardActivity.java
@@ -1,388 +1,46 @@
package com.example.pap_teste;
-import android.content.Intent;
import android.os.Bundle;
-import android.text.Editable;
-import android.text.TextWatcher;
-import android.view.View;
-import android.widget.EditText;
-import android.widget.ImageView;
-import android.widget.ProgressBar;
-import android.widget.TextView;
-
-import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
-import androidx.core.graphics.Insets;
-import androidx.core.view.ViewCompat;
-import androidx.core.view.WindowInsetsCompat;
-import androidx.recyclerview.widget.LinearLayoutManager;
-import androidx.recyclerview.widget.RecyclerView;
-
-import com.example.pap_teste.models.Restaurant;
+import androidx.fragment.app.Fragment;
import com.google.android.material.bottomnavigation.BottomNavigationView;
-import com.google.android.material.chip.Chip;
-import com.google.android.material.chip.ChipGroup;
-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 ClientDashboardActivity extends AppCompatActivity {
- private String email, displayName;
- private TextView txtGreeting;
- private ImageView imgProfile;
- private EditText etSearch;
- private ChipGroup chipGroupCategories;
- private RecyclerView rvFeatured, rvTopRated, rvPizzas, rvSushi, rvCarnes, rvMassas, rvSobremesas;
- private ProgressBar progressBar;
- private View layoutFeatured, layoutTopRated, layoutPizzas, layoutSushi, layoutCarnes, layoutMassas, layoutSobremesas;
-
- private List allRestaurants = new ArrayList<>();
- private List filteredRestaurants = new ArrayList<>();
-
- private FeaturedRestaurantAdapter featuredAdapter, topRatedAdapter, pizzasAdapter, sushiAdapter, carnesAdapter, massasAdapter, sobremesasAdapter;
-
- private final String[] CATEGORIES = { "Tudo", "Carnes", "Massas", "Sushi", "Pizzas", "Sobremesas" };
- private String currentCategoryFilter = "Tudo";
- private String currentSearchFilter = "";
-
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- EdgeToEdge.enable(this);
- setContentView(R.layout.activity_client_dashboard);
+ setContentView(R.layout.activity_client_dashboard_v2);
- ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.clientRoot), (v, insets) -> {
- Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
- v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
- return insets;
- });
-
- email = getIntent().getStringExtra(MainActivity.EXTRA_EMAIL);
- displayName = getIntent().getStringExtra(MainActivity.EXTRA_DISPLAY_NAME);
-
- initViews();
- setupBottomNavigation();
- setupSearch();
- setupCategories();
-
- updateGreeting();
- fetchProfilePicture();
- fetchRestaurants();
- }
-
- private void initViews() {
- txtGreeting = findViewById(R.id.txtClientGreeting);
- imgProfile = findViewById(R.id.imgProfile);
- etSearch = findViewById(R.id.etSearch);
- chipGroupCategories = findViewById(R.id.chipGroupCategories);
- rvFeatured = findViewById(R.id.rvFeatured);
- 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);
- 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));
- 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);
- intent.putExtra("category_filter", restaurant.getCategory());
- startActivity(intent);
- };
-
- featuredAdapter = new FeaturedRestaurantAdapter(new ArrayList<>(), 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);
- 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 -> {
- Intent intent = new Intent(this, ProfileDashboardActivity.class);
- intent.putExtra(MainActivity.EXTRA_EMAIL, email);
- intent.putExtra(MainActivity.EXTRA_DISPLAY_NAME, displayName);
- startActivity(intent);
- });
- }
-
- private void setupBottomNavigation() {
BottomNavigationView bottomNav = findViewById(R.id.bottomNavigation);
+
+ // Initial fragment
+ loadFragment(new HomeFragment());
+
bottomNav.setOnItemSelectedListener(item -> {
+ Fragment fragment = null;
int id = item.getItemId();
+
if (id == R.id.nav_home) {
- return true;
+ fragment = new HomeFragment();
} else if (id == R.id.nav_reservations) {
- Intent intent = new Intent(this, MinhasReservasActivity.class);
- intent.putExtra(MainActivity.EXTRA_EMAIL, email);
- startActivity(intent);
- return false; // Don't highlight if we open new activity
+ fragment = new MyReservationsFragment();
} else if (id == R.id.nav_profile) {
- Intent intent = new Intent(this, ProfileDashboardActivity.class);
- intent.putExtra(MainActivity.EXTRA_EMAIL, email);
- intent.putExtra(MainActivity.EXTRA_DISPLAY_NAME, displayName);
- startActivity(intent);
- return false;
+ fragment = new ProfileFragment();
+ }
+
+ if (fragment != null) {
+ loadFragment(fragment);
+ return true;
}
return false;
});
}
- private void updateGreeting() {
- if (displayName != null && !displayName.isEmpty()) {
- txtGreeting.setText("Olá, " + displayName.split(" ")[0] + "!");
- } else {
- txtGreeting.setText("Olá, Visitante!");
- }
- }
-
- private void fetchProfilePicture() {
- if (email == null)
- return;
- String documentId = email.replace(".", "_").replace("@", "_at_");
- FirebaseDatabase.getInstance().getReference().child("Clientes").child(documentId).child("photoUrl")
- .get().addOnSuccessListener(snapshot -> {
- if (!isDestroyed() && snapshot.exists() && snapshot.getValue(String.class) != null) {
- com.bumptech.glide.Glide.with(this).load(snapshot.getValue(String.class)).circleCrop()
- .into(imgProfile);
- }
- });
- }
-
- private void fetchRestaurants() {
- progressBar.setVisibility(View.VISIBLE);
- layoutFeatured.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() {
- @Override
- public void onDataChange(@androidx.annotation.NonNull DataSnapshot snapshot) {
- progressBar.setVisibility(View.GONE);
- allRestaurants.clear();
-
- for (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);
- Double ratingAvg = ds.child("ratingAvg").getValue(Double.class);
- Integer ratingCount = ds.child("ratingCount").getValue(Integer.class);
-
- if (name != null && email != null) {
- Restaurant r = new Restaurant(name, cat != null ? cat : "Vário", email, false, logoUrl);
- if (ratingAvg != null)
- r.setRatingAvg(ratingAvg);
- if (ratingCount != null)
- r.setRatingCount(ratingCount);
- allRestaurants.add(r);
- }
- }
- }
- applyFilters();
- }
-
- @Override
- public void onCancelled(@androidx.annotation.NonNull DatabaseError error) {
- progressBar.setVisibility(View.GONE);
- }
- });
- }
-
- private void setupCategories() {
- for (String category : CATEGORIES) {
- Chip chip = new Chip(this);
- chip.setText(category);
- chip.setCheckable(true);
- chip.setClickable(true);
- // Default styling
- chip.setChipBackgroundColorResource(R.color.colorSurface);
- chip.setTextColor(getResources().getColor(R.color.colorTextSecondary));
- chip.setChipStrokeWidth(0f);
-
- if (category.equals("Tudo")) {
- chip.setChecked(true);
- chip.setChipBackgroundColorResource(R.color.colorPrimary);
- chip.setTextColor(getResources().getColor(R.color.white));
- }
-
- chip.setOnCheckedChangeListener((buttonView, isChecked) -> {
- if (isChecked) {
- // Reset all other chips visual state
- for (int i = 0; i < chipGroupCategories.getChildCount(); i++) {
- Chip c = (Chip) chipGroupCategories.getChildAt(i);
- if (c != chip) {
- c.setChipBackgroundColorResource(R.color.colorSurface);
- c.setTextColor(getResources().getColor(R.color.colorTextSecondary));
- }
- }
- chip.setChipBackgroundColorResource(R.color.colorPrimary);
- chip.setTextColor(getResources().getColor(R.color.white));
-
- currentCategoryFilter = category;
- applyFilters();
- } else if (currentCategoryFilter.equals(category)) {
- // Prevent unchecking the currently selected chip
- chip.setChecked(true);
- }
- });
- chipGroupCategories.addView(chip);
- }
- }
-
- private void setupSearch() {
- etSearch.addTextChangedListener(new TextWatcher() {
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count, int after) {
- }
-
- @Override
- public void onTextChanged(CharSequence s, int start, int before, int count) {
- currentSearchFilter = s.toString().toLowerCase().trim();
- applyFilters();
- }
-
- @Override
- public void afterTextChanged(Editable s) {
- }
- });
- }
-
- private void applyFilters() {
- filteredRestaurants.clear();
- String normalizedSearch = normalizeString(currentSearchFilter);
-
- for (Restaurant r : allRestaurants) {
- boolean matchesCategory = currentCategoryFilter.equals("Tudo")
- || currentCategoryFilter.equals(r.getCategory());
-
- String normalizedName = normalizeString(r.getName());
- boolean matchesSearch = currentSearchFilter.isEmpty() || normalizedName.contains(normalizedSearch);
-
- if (matchesCategory && matchesSearch) {
- filteredRestaurants.add(r);
- }
- }
-
- // Listas por categorias
- List featuredList = new ArrayList<>();
- 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);
- }
- }
-
- 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);
- 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) {
- if (str == null)
- return "";
- // Remove accents and special marks, and convert to lowercase
- String normalized = java.text.Normalizer.normalize(str, java.text.Normalizer.Form.NFD);
- normalized = normalized.replaceAll("\\p{InCombiningDiacriticalMarks}+", "");
- return normalized.toLowerCase().trim();
+ private void loadFragment(Fragment fragment) {
+ getSupportFragmentManager()
+ .beginTransaction()
+ .replace(R.id.fragmentContainer, fragment)
+ .commit();
}
}
diff --git a/app/src/main/java/com/example/pap_teste/DataSeeder.java b/app/src/main/java/com/example/pap_teste/DataSeeder.java
new file mode 100644
index 0000000..00701c2
--- /dev/null
+++ b/app/src/main/java/com/example/pap_teste/DataSeeder.java
@@ -0,0 +1,75 @@
+package com.example.pap_teste;
+
+import com.example.pap_teste.models.Restaurant;
+import com.google.firebase.firestore.CollectionReference;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class DataSeeder {
+
+ public static void seedRestaurants() {
+ CollectionReference restaurants = FirestoreManager.getInstance().getRestaurantsCollection();
+
+ List sampleRestaurants = new ArrayList<>();
+
+ sampleRestaurants.add(createRestaurant("The Italian Job", "Italian",
+ "Authentic wood-fired pizzas and homemade pasta in a cozy setting.",
+ "https://images.unsplash.com/photo-1555396273-367ea4eb4db5", 4.8, "Rua de Itália, 123, Lisboa"));
+
+ sampleRestaurants.add(createRestaurant("Sushi Zen", "Japanese",
+ "Premium sushi experience with fresh ingredients flown in daily.",
+ "https://images.unsplash.com/photo-1579871494447-9811cf80d66c", 4.9, "Avenida do Japão, 45, Porto"));
+
+ sampleRestaurants.add(createRestaurant("Burger Haven", "Burgers",
+ "Gourmet burgers made with 100% aged beef and unique toppings.",
+ "https://images.unsplash.com/photo-1571091718767-18b5b1457add", 4.5, "Praça do Hambúrguer, 10, Braga"));
+
+ sampleRestaurants.add(createRestaurant("Taco Libre", "Mexican",
+ "Vibrant street-style Mexican food and craft margaritas.",
+ "https://images.unsplash.com/photo-1565299585323-38d6b0865b47", 4.6, "Rua do México, 88, Faro"));
+
+ sampleRestaurants.add(createRestaurant("Steakhouse Prime", "Steakhouse",
+ "Expertly grilled premium cuts and an extensive wine list.",
+ "https://images.unsplash.com/photo-1546241072-48010ad28c2c", 4.7, "Travessa do Bife, 5, Coimbra"));
+
+ sampleRestaurants.add(createRestaurant("Le Petit Bistro", "French",
+ "A slice of Paris serving classic French dishes and fine wine.",
+ "https://images.unsplash.com/photo-1550966842-28a2a2d3efd1", 4.4, "Rua de França, 22, Évora"));
+
+ sampleRestaurants.add(createRestaurant("Green Garden", "Vegetarian",
+ "Sustainable and delicious plant-based cuisine for everyone.",
+ "https://images.unsplash.com/photo-1512621776951-a57141f2eefd", 4.6, "Alameda Verde, 15, Aveiro"));
+
+ sampleRestaurants.add(createRestaurant("Ocean's Catch", "Seafood",
+ "The freshest seafood and shellfish with a beautiful ocean view.",
+ "https://images.unsplash.com/photo-1551248429-42405d2d9cd8", 4.8, "Estrada da Praia, 1, Cascais"));
+
+ for (Restaurant r : sampleRestaurants) {
+ restaurants.document().set(r);
+ }
+ }
+
+ private static Restaurant createRestaurant(String name, String cuisine, String desc, String url, double rating, String address) {
+ Restaurant r = new Restaurant();
+ r.setName(name);
+ r.setCuisine(cuisine);
+ r.setDescription(desc);
+ r.setImageURL(url);
+ r.setRating(rating);
+ r.setAddress(address);
+
+ Map hours = new HashMap<>();
+ hours.put("open", "12:00");
+ hours.put("close", "23:00");
+ r.setOpeningHours(hours);
+
+ List slots = new ArrayList<>();
+ slots.add("12:00"); slots.add("13:00"); slots.add("14:00");
+ slots.add("19:00"); slots.add("20:00"); slots.add("21:00"); slots.add("22:00");
+ r.setAvailableSlots(slots);
+
+ return r;
+ }
+}
diff --git a/app/src/main/java/com/example/pap_teste/DefinicoesAdminActivity.java b/app/src/main/java/com/example/pap_teste/DefinicoesAdminActivity.java
deleted file mode 100644
index 719b7a7..0000000
--- a/app/src/main/java/com/example/pap_teste/DefinicoesAdminActivity.java
+++ /dev/null
@@ -1,228 +0,0 @@
-package com.example.pap_teste;
-
-import android.os.Bundle;
-import android.text.TextUtils;
-import android.widget.Button;
-import android.widget.EditText;
-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 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.HashMap;
-import java.util.Map;
-
-import android.net.Uri;
-import android.content.Intent;
-import android.widget.ImageView;
-import com.bumptech.glide.Glide;
-import com.google.firebase.storage.FirebaseStorage;
-import com.google.firebase.storage.StorageReference;
-import java.util.UUID;
-import androidx.activity.result.ActivityResultLauncher;
-import androidx.activity.result.contract.ActivityResultContracts;
-
-public class DefinicoesAdminActivity extends AppCompatActivity {
-
- private EditText inputRadius, inputAddress;
- private android.widget.Spinner spinnerCategory;
- private ImageView imgLogo;
- private DatabaseReference databaseReference;
- private String documentId;
- private String photoUrl;
- private ActivityResultLauncher imagePickerLauncher;
- private String[] categories = {"Carnes", "Massas", "Sushi", "Pizzas", "Sobremesas", "Italiana", "Moderna"};
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- EdgeToEdge.enable(this);
- setContentView(R.layout.activity_definicoes_admin);
- ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.definicoesRoot), (v, insets) -> {
- Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
- v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
- return insets;
- });
-
- String email = getIntent().getStringExtra(MainActivity.EXTRA_EMAIL);
- if (email != null) {
- documentId = email.replace(".", "_").replace("@", "_at_");
- }
-
- databaseReference = FirebaseDatabase.getInstance().getReference().child("Restaurantes");
-
- inputRadius = findViewById(R.id.inputRadius);
- inputAddress = findViewById(R.id.inputAddress);
- spinnerCategory = findViewById(R.id.spinnerCategory);
- imgLogo = findViewById(R.id.imgRestaurantLogo);
-
- android.widget.ArrayAdapter adapter = new android.widget.ArrayAdapter<>(this,
- android.R.layout.simple_spinner_item, categories);
- adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
- spinnerCategory.setAdapter(adapter);
-
- Button btnSave = findViewById(R.id.btnSaveSettings);
- Button btnBack = findViewById(R.id.btnVoltar);
- Button btnChangeLogo = findViewById(R.id.btnChangeLogo);
-
- if (btnBack != null) {
- btnBack.setOnClickListener(v -> finish());
- }
-
- imagePickerLauncher = registerForActivityResult(
- new ActivityResultContracts.StartActivityForResult(),
- result -> {
- if (result.getResultCode() == RESULT_OK && result.getData() != null) {
- Uri imageUri = result.getData().getData();
- if (imageUri != null) {
- uploadImageToFirebase(imageUri);
- }
- }
- });
-
- btnChangeLogo.setOnClickListener(v -> {
- String[] options = {"Galeria", "URL da Imagem"};
- new androidx.appcompat.app.AlertDialog.Builder(this)
- .setTitle("Escolher Logótipo")
- .setItems(options, (dialog, which) -> {
- if (which == 0) {
- Intent intent = new Intent(Intent.ACTION_PICK);
- intent.setType("image/*");
- imagePickerLauncher.launch(intent);
- } else {
- showUrlInputDialog();
- }
- }).show();
- });
-
- loadCurrentSettings();
-
- btnSave.setOnClickListener(v -> saveSettings());
- }
-
- private void showUrlInputDialog() {
- androidx.appcompat.app.AlertDialog.Builder builder = new androidx.appcompat.app.AlertDialog.Builder(this);
- builder.setTitle("Inserir URL da Imagem");
-
- final EditText input = new EditText(this);
- input.setInputType(android.text.InputType.TYPE_TEXT_VARIATION_URI);
- builder.setView(input);
-
- builder.setPositiveButton("Confirmar", (dialog, which) -> {
- String url = input.getText().toString().trim();
- if (!TextUtils.isEmpty(url)) {
- this.photoUrl = url;
- Glide.with(this).load(photoUrl).circleCrop().into(imgLogo);
- Toast.makeText(this, "Logótipo definido!", Toast.LENGTH_SHORT).show();
- }
- });
- builder.setNegativeButton("Cancelar", (dialog, which) -> dialog.cancel());
- builder.show();
- }
-
- private void uploadImageToFirebase(Uri imageUri) {
- if (documentId == null) return;
-
- StorageReference storageRef = FirebaseStorage.getInstance().getReference()
- .child("restaurant_logos/" + UUID.randomUUID().toString());
-
- storageRef.putFile(imageUri).addOnSuccessListener(taskSnapshot -> {
- storageRef.getDownloadUrl().addOnSuccessListener(uri -> {
- photoUrl = uri.toString();
- Glide.with(this).load(photoUrl).circleCrop().into(imgLogo);
- });
- }).addOnFailureListener(e -> {
- Toast.makeText(this, "Falha no upload: " + e.getMessage(), Toast.LENGTH_LONG).show();
- });
- }
-
- private void loadCurrentSettings() {
- if (documentId == null)
- return;
-
- databaseReference.child(documentId).addListenerForSingleValueEvent(new ValueEventListener() {
- @Override
- public void onDataChange(@NonNull DataSnapshot snapshot) {
- if (snapshot.exists()) {
- if (snapshot.hasChild("securityDistance")) {
- Object val = snapshot.child("securityDistance").getValue();
- inputRadius.setText(val != null ? val.toString() : "");
- }
- if (snapshot.hasChild("address")) {
- String addr = snapshot.child("address").getValue(String.class);
- inputAddress.setText(addr != null ? addr : "");
- }
- if (snapshot.hasChild("category")) {
- String cat = snapshot.child("category").getValue(String.class);
- if (cat != null) {
- for (int i = 0; i < categories.length; i++) {
- if (categories[i].equalsIgnoreCase(cat)) {
- spinnerCategory.setSelection(i);
- break;
- }
- }
- }
- }
- if (snapshot.hasChild("logoUrl")) {
- photoUrl = snapshot.child("logoUrl").getValue(String.class);
- if (photoUrl != null && !photoUrl.isEmpty()) {
- Glide.with(DefinicoesAdminActivity.this).load(photoUrl).circleCrop().into(imgLogo);
- }
- }
- }
- }
-
- @Override
- public void onCancelled(@NonNull DatabaseError error) {
- Toast.makeText(DefinicoesAdminActivity.this, "Erro ao carregar definições.", Toast.LENGTH_SHORT).show();
- }
- });
- }
-
- private void saveSettings() {
- if (documentId == null)
- return;
-
- String radiusStr = inputRadius.getText().toString().trim();
- String addressStr = inputAddress.getText().toString().trim();
- String selectedCategory = spinnerCategory.getSelectedItem().toString();
-
- if (TextUtils.isEmpty(radiusStr) || TextUtils.isEmpty(addressStr)) {
- Toast.makeText(this, "Preencha todos os campos.", Toast.LENGTH_SHORT).show();
- return;
- }
-
- try {
- int radius = Integer.parseInt(radiusStr);
-
- Map updates = new HashMap<>();
- updates.put("securityDistance", radius);
- updates.put("address", addressStr);
- updates.put("category", selectedCategory);
- if (photoUrl != null) {
- updates.put("logoUrl", photoUrl);
- }
-
- databaseReference.child(documentId).updateChildren(updates)
- .addOnSuccessListener(aVoid -> {
- Toast.makeText(this, "Definições guardadas com sucesso!", Toast.LENGTH_SHORT).show();
- finish();
- })
- .addOnFailureListener(
- e -> Toast.makeText(this, "Falha ao guardar definições.", Toast.LENGTH_SHORT).show());
-
- } catch (NumberFormatException e) {
- Toast.makeText(this, "Raio inválido.", Toast.LENGTH_SHORT).show();
- }
- }
-}
diff --git a/app/src/main/java/com/example/pap_teste/DetalhesReservasActivity.java b/app/src/main/java/com/example/pap_teste/DetalhesReservasActivity.java
deleted file mode 100644
index 61e3c5d..0000000
--- a/app/src/main/java/com/example/pap_teste/DetalhesReservasActivity.java
+++ /dev/null
@@ -1,328 +0,0 @@
-package com.example.pap_teste;
-
-import android.os.Bundle;
-import android.widget.ArrayAdapter;
-import android.widget.Button;
-import android.widget.ListView;
-import android.widget.TextView;
-import android.widget.Toast;
-
-import androidx.activity.EdgeToEdge;
-import androidx.appcompat.app.AppCompatActivity;
-import androidx.core.graphics.Insets;
-import androidx.core.view.ViewCompat;
-import androidx.core.view.WindowInsetsCompat;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class DetalhesReservasActivity extends AppCompatActivity {
-
- private final List reservas = new ArrayList<>();
- private ArrayAdapter adapter;
- private ListView listReservas;
- private TextView txtInfo;
- private TextView txtNotas;
- private TextView txtEstado;
- private TextView txtMensagem;
- private Button btnConfirmar, btnRecusar, btnApagar;
- private int selectedIndex = -1;
- private String restaurantEmail;
- private com.google.firebase.database.DatabaseReference databaseReference;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- EdgeToEdge.enable(this);
- setContentView(R.layout.activity_detalhes_reservas);
- ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.detalhesReservasRoot), (v, insets) -> {
- Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
- v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
- return insets;
- });
-
- restaurantEmail = getIntent().getStringExtra(MainActivity.EXTRA_EMAIL);
- if (restaurantEmail == null) {
- if (com.google.firebase.auth.FirebaseAuth.getInstance().getCurrentUser() != null) {
- restaurantEmail = com.google.firebase.auth.FirebaseAuth.getInstance().getCurrentUser().getEmail();
- } else {
- restaurantEmail = "sabor_arte@restaurante.com";
- }
- }
-
- bindViews();
- setupList();
- setupActions();
- loadReservas();
- }
-
- private void bindViews() {
- listReservas = findViewById(R.id.listReservas);
- txtInfo = findViewById(R.id.txtReservaInfo);
- txtNotas = findViewById(R.id.txtReservaNotas);
- txtEstado = findViewById(R.id.txtReservaEstado);
- txtMensagem = findViewById(R.id.txtMensagemReserva);
-
- btnConfirmar = findViewById(R.id.btnConfirmarReserva);
- btnRecusar = findViewById(R.id.btnCancelarReserva);
- btnApagar = findViewById(R.id.btnApagarReserva);
-
- Button back = findViewById(R.id.btnVoltar);
- if (back != null) {
- back.setOnClickListener(v -> finish());
- }
- }
-
- private void loadReservas() {
- databaseReference = com.google.firebase.database.FirebaseDatabase.getInstance().getReference("reservas");
- databaseReference.addValueEventListener(new com.google.firebase.database.ValueEventListener() {
- @Override
- public void onDataChange(
- @androidx.annotation.NonNull com.google.firebase.database.DataSnapshot snapshot) {
- reservas.clear();
- String targetEmail = restaurantEmail != null ? restaurantEmail.trim() : "";
- for (com.google.firebase.database.DataSnapshot data : snapshot.getChildren()) {
- com.example.pap_teste.models.Reserva r = data
- .getValue(com.example.pap_teste.models.Reserva.class);
- if (r != null && r.getEstado() != null && !"Arquivada".equals(r.getEstado())) {
- String rEmail = r.getRestauranteEmail();
- if (rEmail != null && rEmail.trim().equalsIgnoreCase(targetEmail)) {
- reservas.add(r);
- }
- }
- }
- refreshList();
- }
-
- @Override
- public void onCancelled(
- @androidx.annotation.NonNull com.google.firebase.database.DatabaseError error) {
- Toast.makeText(DetalhesReservasActivity.this, "Erro ao carregar reservas.", Toast.LENGTH_SHORT)
- .show();
- }
- });
- }
-
- private void setupList() {
- adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_activated_1);
- listReservas.setAdapter(adapter);
-
- listReservas.setOnItemClickListener((parent, view, position, id) -> {
- selectedIndex = position;
- mostrarDetalhe(reservas.get(position));
- });
- }
-
- private void setupActions() {
- if (btnConfirmar != null) {
- btnConfirmar.setOnClickListener(v -> {
- com.example.pap_teste.models.Reserva item = reservas.get(selectedIndex);
- if ("Pendente".equals(item.getEstado())) {
- mostrarMesasDisponiveis();
- } else if (item.getEstado() != null && item.getEstado().startsWith("Confirmada")) {
- atualizarEstadoSelecionado("Concluída");
- }
- });
- }
-
- if (btnRecusar != null) {
- btnRecusar.setOnClickListener(v -> showRecusarDialog());
- }
-
- if (btnApagar != null) {
- btnApagar.setOnClickListener(v -> apagarReserva());
- }
- }
-
- 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;
-
- String[] motivos = { "Sem espaço no restaurante", "Fora de horas", "Reserva duplicada", "Outro" };
- new androidx.appcompat.app.AlertDialog.Builder(this)
- .setTitle("Motivo da Recusa")
- .setItems(motivos, (dialog, which) -> {
- atualizarEstadoSelecionado("Recusada (" + motivos[which] + ")");
- })
- .setNegativeButton("Voltar", null)
- .show();
- }
-
- private void apagarReserva() {
- if (selectedIndex < 0)
- return;
-
- new androidx.appcompat.app.AlertDialog.Builder(this)
- .setTitle("Apagar/Arquivar Reserva")
- .setMessage("Tem a certeza que deseja limpar esta reserva da lista?")
- .setPositiveButton("Sim", (dialog, which) -> {
- com.example.pap_teste.models.Reserva r = reservas.get(selectedIndex);
- String idReserva = r.getId();
-
- if ("Concluída".equals(r.getEstado()) || r.getEstado().startsWith("Confirmada")) {
- databaseReference.child(idReserva).child("estado").setValue("Arquivada").addOnCompleteListener(task -> {
- if (task.isSuccessful()) {
- clearSelectionAndShowMessage();
- }
- });
- } else {
- databaseReference.child(idReserva).removeValue().addOnCompleteListener(task -> {
- if (task.isSuccessful()) {
- clearSelectionAndShowMessage();
- }
- });
- }
- })
- .setNegativeButton("Voltar", null)
- .show();
- }
-
- private void clearSelectionAndShowMessage() {
- selectedIndex = -1;
- txtInfo.setText("Selecione uma reserva");
- txtNotas.setText("");
- txtEstado.setText("Estado:");
- txtMensagem.setText("Reserva processada e apagada da vista.");
- toggleButtons(null);
- }
-
- private void atualizarEstadoSelecionado(String novoEstado) {
- if (selectedIndex < 0 || selectedIndex >= reservas.size()) {
- Toast.makeText(this, "Selecione uma reserva para atualizar.", Toast.LENGTH_SHORT).show();
- return;
- }
-
- com.example.pap_teste.models.Reserva item = reservas.get(selectedIndex);
- databaseReference.child(item.getId()).child("estado").setValue(novoEstado).addOnCompleteListener(task -> {
- if (task.isSuccessful()) {
- txtMensagem
- .setText(String.format("Reserva de %s marcada como %s.", item.getClienteEmail(), novoEstado));
- mostrarDetalhe(item);
- }
- });
- }
-
- private void mostrarDetalhe(com.example.pap_teste.models.Reserva item) {
- txtInfo.setText(String.format("%s • %s • %s • %dp", item.getClienteEmail(), item.getRestauranteName(),
- item.getHora(), item.getPessoas()));
- txtNotas.setText("Data: " + item.getData());
- txtEstado.setText(String.format("Estado: %s", item.getEstado()));
- toggleButtons(item);
- }
-
- private void toggleButtons(com.example.pap_teste.models.Reserva item) {
- if (item == null) {
- btnConfirmar.setVisibility(android.view.View.GONE);
- btnRecusar.setVisibility(android.view.View.GONE);
- btnApagar.setVisibility(android.view.View.GONE);
- return;
- }
-
- 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);
- }
- }
-
- private void refreshList() {
- adapter.clear();
- for (com.example.pap_teste.models.Reserva item : reservas) {
- String resumo = String.format("%s - %s (%s) • %s", item.getHora(), item.getData(), item.getEstado(),
- item.getClienteEmail());
- adapter.add(resumo);
- }
- adapter.notifyDataSetChanged();
- }
-}
diff --git a/app/src/main/java/com/example/pap_teste/EstablishmentDashboardActivity.java b/app/src/main/java/com/example/pap_teste/EstablishmentDashboardActivity.java
index bd2389e..b237757 100644
--- a/app/src/main/java/com/example/pap_teste/EstablishmentDashboardActivity.java
+++ b/app/src/main/java/com/example/pap_teste/EstablishmentDashboardActivity.java
@@ -1,263 +1,13 @@
package com.example.pap_teste;
-import android.content.Intent;
import android.os.Bundle;
-import android.widget.Button;
-import android.widget.TextView;
-
-import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
-import androidx.core.graphics.Insets;
-import androidx.core.view.ViewCompat;
-import androidx.core.view.WindowInsetsCompat;
public class EstablishmentDashboardActivity extends AppCompatActivity {
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- EdgeToEdge.enable(this);
- setContentView(R.layout.activity_establishment_dashboard);
- ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.establishmentRoot), (v, insets) -> {
- Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
- v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
- return insets;
- });
-
- TextView txtTitle = findViewById(R.id.txtEstabTitle);
- TextView txtSubtitle = findViewById(R.id.txtEstabSubtitle);
- TextView txtRole = findViewById(R.id.txtEstabRole);
-
- String actionMode = getIntent().getStringExtra(MainActivity.EXTRA_ACTION_MODE);
- String displayName = getIntent().getStringExtra(MainActivity.EXTRA_DISPLAY_NAME);
- String role = getIntent().getStringExtra(MainActivity.EXTRA_ROLE);
-
- boolean isNewAccount = "CRIAR".equalsIgnoreCase(actionMode);
- txtTitle.setText(displayName != null ? displayName : "Estabelecimento");
- txtRole.setText(String.format("Função: %s", role != null ? role : "ADMIN"));
- txtSubtitle.setText(isNewAccount
- ? "Perfil criado. Configure horários, mesas e abra reservas."
- : "Dashboard operacional. Acompanhe as reservas em tempo real.");
-
- android.view.View btnOpenWalkIns = findViewById(R.id.btnAbrirEspera);
- android.view.View btnStaff = findViewById(R.id.btnGestaoStaff);
- android.view.View btnGerirMesas = findViewById(R.id.btnGerirMesas);
- android.view.View btnDetails = findViewById(R.id.btnDetalhesReservas);
- android.view.View btnSettings = findViewById(R.id.btnDefinicoes);
-
- com.google.android.material.appbar.MaterialToolbar toolbar = findViewById(R.id.toolbar);
- if (toolbar != null) {
- toolbar.setNavigationOnClickListener(v -> finish());
- }
-
- String email = getIntent().getStringExtra(MainActivity.EXTRA_EMAIL);
- if (email == null) {
- if (com.google.firebase.auth.FirebaseAuth.getInstance().getCurrentUser() != null) {
- email = com.google.firebase.auth.FirebaseAuth.getInstance().getCurrentUser().getEmail();
- } else {
- return; // Can't proceed without email
- }
- }
- final String finalEmail = email;
-
- if (btnOpenWalkIns != null) {
- btnOpenWalkIns.setOnClickListener(v -> {
- Intent intent = new Intent(this, ListaEsperaActivity.class);
- intent.putExtra(MainActivity.EXTRA_EMAIL, finalEmail);
- startActivity(intent);
- });
- }
-
- if (btnStaff != null) {
- btnStaff.setOnClickListener(v -> {
- Intent intent = new Intent(this, GestaoStaffActivity.class);
- intent.putExtra(MainActivity.EXTRA_EMAIL, finalEmail);
- startActivity(intent);
- });
- }
-
- if (btnGerirMesas != null) {
- btnGerirMesas.setOnClickListener(v -> {
- Intent intent = new Intent(this, GerirMesasActivity.class);
- intent.putExtra(MainActivity.EXTRA_EMAIL, finalEmail);
- startActivity(intent);
- });
- }
-
- if (btnDetails != null) {
- btnDetails.setOnClickListener(v -> {
- Intent intent = new Intent(this, DetalhesReservasActivity.class);
- intent.putExtra(MainActivity.EXTRA_EMAIL, finalEmail);
- startActivity(intent);
- });
- }
-
- if (btnSettings != null) {
- btnSettings.setOnClickListener(v -> {
- Intent intent = new Intent(this, DefinicoesAdminActivity.class);
- intent.putExtra(MainActivity.EXTRA_EMAIL, finalEmail);
- startActivity(intent);
- });
- }
-
- android.view.View cardReservasHoje = findViewById(R.id.cardReservasHoje);
- if (cardReservasHoje != null) {
- cardReservasHoje.setOnClickListener(v -> {
- Intent intent = new Intent(this, DetalhesReservasActivity.class);
- intent.putExtra(MainActivity.EXTRA_EMAIL, finalEmail);
- startActivity(intent);
- });
- }
-
- loadProximasReservas();
- loadEstatisticas();
- }
-
- private void loadProximasReservas() {
- android.widget.LinearLayout llProximasReservas = findViewById(R.id.llProximasReservas);
- String email = getIntent().getStringExtra(MainActivity.EXTRA_EMAIL);
- if (email == null) {
- if (com.google.firebase.auth.FirebaseAuth.getInstance().getCurrentUser() != null) {
- email = com.google.firebase.auth.FirebaseAuth.getInstance().getCurrentUser().getEmail();
- } else {
- return;
- }
- }
-
- final String targetEmail = email != null ? email.trim() : "";
-
- java.util.Calendar cal = java.util.Calendar.getInstance();
- String todayDate = cal.get(java.util.Calendar.DAY_OF_MONTH) + "/" +
- (cal.get(java.util.Calendar.MONTH) + 1) + "/" +
- cal.get(java.util.Calendar.YEAR);
-
- com.google.firebase.database.FirebaseDatabase.getInstance().getReference("reservas")
- .addValueEventListener(new com.google.firebase.database.ValueEventListener() {
- @Override
- public void onDataChange(@androidx.annotation.NonNull com.google.firebase.database.DataSnapshot snapshot) {
- llProximasReservas.removeAllViews();
- boolean found = false;
-
- 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.getEstado() != null && (r.getEstado().startsWith("Confirmada") || r.getEstado().equals("Concluída")) && todayDate.equals(r.getData())) {
- String rEmail = r.getRestauranteEmail();
- if (rEmail != null && rEmail.trim().equalsIgnoreCase(targetEmail)) {
- found = true;
- addReservaView(llProximasReservas, r);
- }
- }
- }
-
- if (!found) {
- TextView empty = new TextView(EstablishmentDashboardActivity.this);
- empty.setText("Não há reservas confirmadas para hoje.");
- empty.setTextColor(android.graphics.Color.parseColor("#5F5F5F"));
- empty.setTextSize(14f);
- llProximasReservas.addView(empty);
- }
- }
-
- @Override
- public void onCancelled(@androidx.annotation.NonNull com.google.firebase.database.DatabaseError error) {
- }
- });
- }
-
- private void addReservaView(android.widget.LinearLayout container, com.example.pap_teste.models.Reserva r) {
- TextView title = new TextView(this);
- title.setText(String.format("%s - %s", r.getHora(), r.getData()));
- title.setTextColor(android.graphics.Color.BLACK);
- title.setTextSize(16f);
- title.setTypeface(null, android.graphics.Typeface.BOLD);
-
- TextView subtitle = new TextView(this);
- subtitle.setText(String.format("Cliente: %s • %d pessoas", r.getClienteEmail(), r.getPessoas()));
- subtitle.setTextColor(android.graphics.Color.parseColor("#5F5F5F"));
- subtitle.setTextSize(14f);
-
- android.widget.LinearLayout.LayoutParams params = new android.widget.LinearLayout.LayoutParams(
- android.widget.LinearLayout.LayoutParams.MATCH_PARENT, android.widget.LinearLayout.LayoutParams.WRAP_CONTENT);
- subtitle.setLayoutParams(params);
-
- android.view.View divider = new android.view.View(this);
- android.widget.LinearLayout.LayoutParams divParams = new android.widget.LinearLayout.LayoutParams(
- android.widget.LinearLayout.LayoutParams.MATCH_PARENT, 2);
- divParams.setMargins(0, 24, 0, 24);
- divider.setLayoutParams(divParams);
- divider.setBackgroundColor(android.graphics.Color.parseColor("#EEEEEE"));
-
- container.addView(title);
- container.addView(subtitle);
- container.addView(divider);
- }
-
- private void loadEstatisticas() {
- TextView txtReservasHoje = findViewById(R.id.txtReservasHojeDash);
- TextView txtMesasLivres = findViewById(R.id.txtMesasLivresDash);
- TextView txtListaEspera = findViewById(R.id.txtListaEsperaDash);
-
- String email = getIntent().getStringExtra(MainActivity.EXTRA_EMAIL);
- if (email == null) {
- if (com.google.firebase.auth.FirebaseAuth.getInstance().getCurrentUser() != null) {
- email = com.google.firebase.auth.FirebaseAuth.getInstance().getCurrentUser().getEmail();
- } else {
- return;
- }
- }
- final String finalEmail = email != null ? email.trim() : "";
-
- java.util.Calendar cal = java.util.Calendar.getInstance();
- String todayDate = cal.get(java.util.Calendar.DAY_OF_MONTH) + "/" +
- (cal.get(java.util.Calendar.MONTH) + 1) + "/" +
- cal.get(java.util.Calendar.YEAR);
-
- com.google.firebase.database.DatabaseReference refReservas = com.google.firebase.database.FirebaseDatabase.getInstance().getReference("reservas");
- refReservas.addValueEventListener(new com.google.firebase.database.ValueEventListener() {
- @Override
- public void onDataChange(@androidx.annotation.NonNull com.google.firebase.database.DataSnapshot snapshot) {
- int reservasHoje = 0;
- int listaEspera = 0;
- 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(finalEmail)) {
- if (r.getEstado() != null) {
- // Opção B: Conta TODAS as reservas confirmadas/concluídas/arquivadas
- if (r.getEstado().startsWith("Confirmada") || r.getEstado().equals("Concluída") || r.getEstado().equals("Arquivada")) {
- reservasHoje++;
- } else if ("Pendente".equals(r.getEstado())) {
- listaEspera++;
- }
- }
- }
- }
- if (txtReservasHoje != null) txtReservasHoje.setText(String.format(java.util.Locale.US, "%02d", reservasHoje));
- if (txtListaEspera != null) txtListaEspera.setText(String.format(java.util.Locale.US, "%02d", listaEspera));
- }
-
- @Override
- public void onCancelled(@androidx.annotation.NonNull com.google.firebase.database.DatabaseError error) {
- }
- });
-
- com.google.firebase.database.FirebaseDatabase.getInstance().getReference("Mesas")
- .addValueEventListener(new com.google.firebase.database.ValueEventListener() {
- @Override
- public void onDataChange(@androidx.annotation.NonNull com.google.firebase.database.DataSnapshot snapshot) {
- int mesasLivres = 0;
- for (com.google.firebase.database.DataSnapshot ds : snapshot.getChildren()) {
- com.example.pap_teste.models.Mesa mesa = ds.getValue(com.example.pap_teste.models.Mesa.class);
- if (mesa != null && mesa.getRestauranteEmail() != null && mesa.getRestauranteEmail().trim().equalsIgnoreCase(finalEmail)) {
- if ("Livre".equalsIgnoreCase(mesa.getEstado())) {
- mesasLivres++;
- }
- }
- }
- if (txtMesasLivres != null) txtMesasLivres.setText(String.format(java.util.Locale.US, "%02d", mesasLivres));
- }
- @Override
- public void onCancelled(@androidx.annotation.NonNull com.google.firebase.database.DatabaseError error) {
- }
- });
- }
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ // Temporariamente usando o layout do cliente ou um placeholder se necessário
+ setContentView(R.layout.activity_client_dashboard);
+ }
}
diff --git a/app/src/main/java/com/example/pap_teste/FeaturedRestaurantAdapter.java b/app/src/main/java/com/example/pap_teste/FeaturedRestaurantAdapter.java
index 61b457e..de49eef 100644
--- a/app/src/main/java/com/example/pap_teste/FeaturedRestaurantAdapter.java
+++ b/app/src/main/java/com/example/pap_teste/FeaturedRestaurantAdapter.java
@@ -132,10 +132,10 @@ public class FeaturedRestaurantAdapter extends RecyclerView.Adapter mesas = new ArrayList<>();
- private ArrayAdapter adapter;
- private ListView listMesas;
- private EditText inputNumero;
- private EditText inputCapacidade;
- private Spinner spinnerEstado;
- private TextView txtMensagem;
- private DatabaseReference mDatabase;
- private Mesa selectedMesa = null;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- EdgeToEdge.enable(this);
- setContentView(R.layout.activity_gerir_mesas);
- ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.gerirMesasRoot), (v, insets) -> {
- Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
- v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
- return insets;
- });
-
- bindViews();
-
- mDatabase = FirebaseDatabase.getInstance().getReference("Mesas");
-
- setupList();
- setupFormActions();
- }
-
- private void bindViews() {
- listMesas = findViewById(R.id.listMesas);
- inputNumero = findViewById(R.id.inputMesaNumero);
- inputCapacidade = findViewById(R.id.inputMesaCapacidade);
- spinnerEstado = findViewById(R.id.spinnerEstadoMesa);
- txtMensagem = findViewById(R.id.txtMensagemMesa);
-
- Button back = findViewById(R.id.btnVoltar);
- if (back != null) {
- back.setOnClickListener(v -> finish());
- }
-
- ArrayAdapter estadoAdapter = new ArrayAdapter<>(
- this,
- android.R.layout.simple_spinner_dropdown_item,
- new String[] { "Livre", "Ocupada", "Reservada" });
- spinnerEstado.setAdapter(estadoAdapter);
- }
-
- private void setupList() {
- adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_activated_1);
- listMesas.setAdapter(adapter);
-
- mDatabase.addValueEventListener(new ValueEventListener() {
- @Override
- public void onDataChange(@NonNull DataSnapshot snapshot) {
- mesas.clear();
- adapter.clear();
- String currentUserEmail = FirebaseAuth.getInstance().getCurrentUser() != null
- ? FirebaseAuth.getInstance().getCurrentUser().getEmail()
- : "";
- for (DataSnapshot postSnapshot : snapshot.getChildren()) {
- Mesa mesa = postSnapshot.getValue(Mesa.class);
- if (mesa != null && (mesa.getRestauranteEmail() == null || mesa.getRestauranteEmail().equals(currentUserEmail))) {
- // Ensure the ID is set from the snapshot key if it's missing in the value
- mesa.setId(postSnapshot.getKey());
- mesas.add(mesa);
- String resumo = String.format("Mesa %02d • %d lugares • %s", mesa.getNumero(),
- mesa.getCapacidade(), mesa.getEstado());
- adapter.add(resumo);
- }
- }
- adapter.notifyDataSetChanged();
- }
-
- @Override
- public void onCancelled(@NonNull DatabaseError error) {
- Toast.makeText(GerirMesasActivity.this, "Erro ao carregar mesas: " + error.getMessage(),
- Toast.LENGTH_SHORT).show();
- }
- });
-
- listMesas.setOnItemClickListener((parent, view, position, id) -> {
- Mesa item = mesas.get(position);
- selectedMesa = item;
- inputNumero.setText(String.valueOf(item.getNumero()));
- inputCapacidade.setText(String.valueOf(item.getCapacidade()));
- spinnerEstado.setSelection(getEstadoIndex(item.getEstado()));
- txtMensagem.setText(String.format("Editar mesa %d", item.getNumero()));
- });
- }
-
- private int getEstadoIndex(String estado) {
- if ("Ocupada".equalsIgnoreCase(estado)) {
- return 1;
- }
- if ("Reservada".equalsIgnoreCase(estado)) {
- return 2;
- }
- return 0;
- }
-
- private void setupFormActions() {
- Button btnGuardar = findViewById(R.id.btnGuardarMesa);
- if (btnGuardar != null) {
- btnGuardar.setOnClickListener(v -> guardarMesa());
- }
-
- Button btnRemover = findViewById(R.id.btnRemoverMesa);
- if (btnRemover != null) {
- btnRemover.setOnClickListener(v -> removerMesa());
- }
- }
-
- private void removerMesa() {
- if (selectedMesa == null || selectedMesa.getId() == null) {
- Toast.makeText(this, "Selecione uma mesa válida para remover.", Toast.LENGTH_SHORT).show();
- return;
- }
-
- mDatabase.child(selectedMesa.getId()).removeValue()
- .addOnSuccessListener(aVoid -> {
- Toast.makeText(this, "Mesa removida com sucesso.", Toast.LENGTH_SHORT).show();
- limparCampos();
- })
- .addOnFailureListener(e -> {
- Toast.makeText(this, "Erro ao remover mesa: " + e.getMessage(), Toast.LENGTH_SHORT).show();
- });
- }
-
- private void limparCampos() {
- inputNumero.setText("");
- inputCapacidade.setText("");
- selectedMesa = null;
- txtMensagem.setText("");
- }
-
- private void guardarMesa() {
- String numeroStr = inputNumero.getText().toString().trim();
- String capacidadeStr = inputCapacidade.getText().toString().trim();
- String estado = (String) spinnerEstado.getSelectedItem();
-
- if (numeroStr.isEmpty() || capacidadeStr.isEmpty() || estado == null) {
- Toast.makeText(this, "Preencha número, capacidade e estado.", Toast.LENGTH_SHORT).show();
- return;
- }
-
- int numero;
- int capacidade;
- try {
- numero = Integer.parseInt(numeroStr);
- capacidade = Integer.parseInt(capacidadeStr);
- } catch (NumberFormatException e) {
- Toast.makeText(this, "Use apenas números válidos.", Toast.LENGTH_SHORT).show();
- return;
- }
-
- Mesa existente = findMesa(numero);
- String mesaId;
- String currentUserEmail = FirebaseAuth.getInstance().getCurrentUser() != null
- ? FirebaseAuth.getInstance().getCurrentUser().getEmail()
- : "";
-
- if (existente == null) {
- mesaId = mDatabase.push().getKey();
- Mesa novaMesa = new Mesa(mesaId, numero, capacidade, estado, currentUserEmail);
- if (mesaId != null) {
- mDatabase.child(mesaId).setValue(novaMesa);
- }
- txtMensagem.setText(String.format("Mesa %d adicionada.", numero));
- } else {
- mesaId = existente.getId();
- if (mesaId == null) {
- Toast.makeText(this, "Erro ao atualizar: ID não encontrado.", Toast.LENGTH_SHORT).show();
- return;
- }
- existente.setCapacidade(capacidade);
- existente.setEstado(estado);
- mDatabase.child(mesaId).setValue(existente);
- txtMensagem.setText(String.format("Mesa %d atualizada.", numero));
- }
-
- // Clearing inputs
- limparCampos();
- }
-
- private Mesa findMesa(int numero) {
- for (Mesa item : mesas) {
- if (item.getNumero() == numero) {
- return item;
- }
- }
- return null;
- }
-
-}
diff --git a/app/src/main/java/com/example/pap_teste/GestaoStaffActivity.java b/app/src/main/java/com/example/pap_teste/GestaoStaffActivity.java
deleted file mode 100644
index 2082f37..0000000
--- a/app/src/main/java/com/example/pap_teste/GestaoStaffActivity.java
+++ /dev/null
@@ -1,295 +0,0 @@
-package com.example.pap_teste;
-
-import com.example.pap_teste.models.Mesa;
-import com.example.pap_teste.models.Staff;
-import com.google.android.material.floatingactionbutton.FloatingActionButton;
-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 androidx.annotation.NonNull;
-
-import android.content.Intent;
-import android.os.Bundle;
-import android.view.View;
-import android.widget.ArrayAdapter;
-import android.widget.Button;
-
-import android.widget.ListView;
-import android.widget.Spinner;
-import android.widget.TextView;
-import android.widget.Toast;
-
-import androidx.activity.EdgeToEdge;
-import androidx.appcompat.app.AppCompatActivity;
-import androidx.core.graphics.Insets;
-import androidx.core.view.ViewCompat;
-import androidx.core.view.WindowInsetsCompat;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class GestaoStaffActivity extends AppCompatActivity {
-
- private final List staffList = new ArrayList<>();
- private ArrayAdapter staffAdapter;
- private ListView listStaffMesas;
-
- private Spinner spinnerNomeStaff;
- private Spinner spinnerMesaStaff;
- private TextView txtMensagemStaff;
-
- private DatabaseReference staffRef;
- private DatabaseReference mesasRef;
-
- private List staffNames = new ArrayList<>();
- private List mesasDisponiveis = new ArrayList<>();
- private ArrayAdapter staffNameAdapter;
- private ArrayAdapter mesaSpinnerAdapter;
-
- private FloatingActionButton floatingActionButton;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- EdgeToEdge.enable(this);
- setContentView(R.layout.activity_gestao_staff);
- ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.gestaoStaffRoot), (v, insets) -> {
- Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
- v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
- return insets;
- });
-
- staffRef = FirebaseDatabase.getInstance().getReference("Staff");
- mesasRef = FirebaseDatabase.getInstance().getReference("Mesas");
-
- Button back = findViewById(R.id.btnVoltar);
- if (back != null) {
- back.setOnClickListener(v -> finish());
- }
-
- bindViews();
- setupMesaSpinner();
- setupList();
- setupFormActions();
- }
-
- private void bindViews() {
- listStaffMesas = findViewById(R.id.listStaffMesas);
- spinnerNomeStaff = findViewById(R.id.spinnerNomeStaff);
- spinnerMesaStaff = findViewById(R.id.spinnerMesaStaff);
- txtMensagemStaff = findViewById(R.id.txtMensagemStaff);
- floatingActionButton = findViewById(R.id.floatingActionButton);
- }
-
- /**
- * Preenche o spinner com uma lista simples de mesas (1–20).
- * Mais tarde isto pode ser ligado às mesas reais configuradas em "Gerir Mesas".
- */
- private void setupMesaSpinner() {
- mesaSpinnerAdapter = new ArrayAdapter<>(
- this,
- android.R.layout.simple_spinner_dropdown_item);
-
- staffNameAdapter = new ArrayAdapter<>(
- this,
- android.R.layout.simple_spinner_dropdown_item,
- staffNames);
- spinnerNomeStaff.setAdapter(staffNameAdapter);
-
- loadStaffMembers();
- loadMesas();
-
- spinnerMesaStaff.setAdapter(mesaSpinnerAdapter);
- }
-
- private void loadMesas() {
- mesasRef.addValueEventListener(new ValueEventListener() {
- @Override
- public void onDataChange(@NonNull DataSnapshot snapshot) {
- mesasDisponiveis.clear();
- mesaSpinnerAdapter.clear();
- for (DataSnapshot postSnapshot : snapshot.getChildren()) {
- Mesa mesa = postSnapshot.getValue(Mesa.class);
- if (mesa != null) {
- mesasDisponiveis.add(mesa);
- mesaSpinnerAdapter.add("Mesa " + mesa.getNumero());
- }
- }
- mesaSpinnerAdapter.notifyDataSetChanged();
- }
-
- @Override
- public void onCancelled(@NonNull DatabaseError error) {
- Toast.makeText(GestaoStaffActivity.this, "Erro ao carregar mesas.", Toast.LENGTH_SHORT).show();
- }
- });
- }
-
- private void setupList() {
- staffAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_activated_1);
- listStaffMesas.setAdapter(staffAdapter);
-
- listStaffMesas.setOnItemClickListener((parent, view, position, id) -> {
- Staff item = staffList.get(position);
- // Select staff in spinner
- int staffIndex = staffNames.indexOf(item.getName());
- if (staffIndex >= 0) {
- spinnerNomeStaff.setSelection(staffIndex);
- }
- // Select mesa in spinner
- // Simple string matching for now since Mesa is stored as String in Staff
- String assignedMesa = item.getMesa();
- if (assignedMesa != null) {
- for (int i = 0; i < mesaSpinnerAdapter.getCount(); i++) {
- if (mesaSpinnerAdapter.getItem(i).equals(assignedMesa)) {
- spinnerMesaStaff.setSelection(i);
- break;
- }
- }
- }
-
- txtMensagemStaff.setText(String.format("A editar: %s", item.getName()));
- });
- }
-
- private void setupFormActions() {
- Button btnAtribuir = findViewById(R.id.btnAtribuirStaff);
- if (btnAtribuir != null) {
- btnAtribuir.setOnClickListener(v -> guardarAtribuicao());
- }
-
- Button btnEliminar = findViewById(R.id.btnEliminarStaff);
- if (btnEliminar != null) {
- btnEliminar.setOnClickListener(v -> eliminarStaff());
- }
-
- if (floatingActionButton != null) {
- floatingActionButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- Intent intent = new Intent(GestaoStaffActivity.this, AddStaffActivity.class);
- startActivity(intent);
- }
- });
- }
-
- Button btnGerirMesas = findViewById(R.id.btnGerirMesasStaff);
- if (btnGerirMesas != null) {
- btnGerirMesas.setOnClickListener(v -> {
- Intent intent = new Intent(GestaoStaffActivity.this, GerirMesasActivity.class);
- startActivity(intent);
- });
- }
- }
-
- private void guardarAtribuicao() {
- String nome = "";
- if (spinnerNomeStaff.getSelectedItem() != null) {
- nome = spinnerNomeStaff.getSelectedItem().toString();
- }
-
- if (nome.isEmpty()) {
- Toast.makeText(this, "Selecione um funcionário.", Toast.LENGTH_SHORT).show();
- return;
- }
-
- if (spinnerMesaStaff == null || spinnerMesaStaff.getSelectedItem() == null) {
- Toast.makeText(this, "Selecione uma mesa.", Toast.LENGTH_SHORT).show();
- return;
- }
-
- String mesaSelecionada = spinnerMesaStaff.getSelectedItem().toString();
-
- Staff staffToUpdate = findByNome(nome);
- if (staffToUpdate != null) {
- staffToUpdate.setMesa(mesaSelecionada);
-
- final String finalNome = nome;
- final String finalMesa = mesaSelecionada;
-
- staffRef.child(staffToUpdate.getId()).setValue(staffToUpdate)
- .addOnSuccessListener(aVoid -> {
- txtMensagemStaff.setText(String.format("%s atribuído à %s.", finalNome, finalMesa));
- })
- .addOnFailureListener(e -> {
- Toast.makeText(this, "Erro ao atualizar: " + e.getMessage(), Toast.LENGTH_SHORT).show();
- });
- } else {
- Toast.makeText(this, "Erro: Staff não encontrado.", Toast.LENGTH_SHORT).show();
- }
- }
-
- private void eliminarStaff() {
- String nome = "";
- if (spinnerNomeStaff.getSelectedItem() != null) {
- nome = spinnerNomeStaff.getSelectedItem().toString();
- }
-
- if (nome.isEmpty()) {
- Toast.makeText(this, "Selecione um funcionário primeiro.", Toast.LENGTH_SHORT).show();
- return;
- }
-
- Staff staffToDelete = findByNome(nome);
- if (staffToDelete != null) {
- new androidx.appcompat.app.AlertDialog.Builder(this)
- .setTitle("Eliminar Staff")
- .setMessage("Tem a certeza que deseja eliminar o funcionário " + staffToDelete.getName() + "?")
- .setPositiveButton("Eliminar", (dialog, which) -> {
- staffRef.child(staffToDelete.getId()).removeValue()
- .addOnSuccessListener(aVoid -> {
- txtMensagemStaff.setText(staffToDelete.getName() + " foi eliminado.");
- })
- .addOnFailureListener(e -> {
- Toast.makeText(this, "Erro ao eliminar: " + e.getMessage(), Toast.LENGTH_SHORT).show();
- });
- })
- .setNegativeButton("Cancelar", null)
- .show();
- } else {
- Toast.makeText(this, "Staff não encontrado.", Toast.LENGTH_SHORT).show();
- }
- }
-
- private Staff findByNome(String nome) {
- for (Staff item : staffList) {
- if (item.getName().equalsIgnoreCase(nome)) {
- return item;
- }
- }
- return null;
- }
-
- private void loadStaffMembers() {
- staffRef.addValueEventListener(new ValueEventListener() {
- @Override
- public void onDataChange(@NonNull DataSnapshot snapshot) {
- staffList.clear();
- staffNames.clear();
- staffAdapter.clear();
-
- for (DataSnapshot postSnapshot : snapshot.getChildren()) {
- Staff staff = postSnapshot.getValue(Staff.class);
- if (staff != null && staff.getName() != null) {
- staffList.add(staff);
- staffNames.add(staff.getName());
-
- String mesaInfo = staff.getMesa() != null ? staff.getMesa() : "Sem Mesa";
- String resumo = String.format("%s • %s • %s", staff.getName(), staff.getZona(), mesaInfo);
- staffAdapter.add(resumo);
- }
- }
-
- staffNameAdapter.notifyDataSetChanged();
- staffAdapter.notifyDataSetChanged();
- }
-
- @Override
- public void onCancelled(@NonNull DatabaseError error) {
- Toast.makeText(GestaoStaffActivity.this, "Erro ao carregar staff.", Toast.LENGTH_SHORT).show();
- }
- });
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/pap_teste/HomeFragment.java b/app/src/main/java/com/example/pap_teste/HomeFragment.java
new file mode 100644
index 0000000..489a3bd
--- /dev/null
+++ b/app/src/main/java/com/example/pap_teste/HomeFragment.java
@@ -0,0 +1,81 @@
+package com.example.pap_teste;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+import com.example.pap_teste.models.Restaurant;
+import com.google.firebase.firestore.FirebaseFirestore;
+import com.google.firebase.firestore.QueryDocumentSnapshot;
+import java.util.ArrayList;
+import java.util.List;
+
+public class HomeFragment extends Fragment {
+
+ private RecyclerView rvFeatured, rvNearYou;
+ private RestaurantAdapter featuredAdapter, nearYouAdapter;
+ private List featuredList = new ArrayList<>();
+ private List nearYouList = new ArrayList<>();
+ private FirebaseFirestore db;
+
+ @Nullable
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ View view = inflater.inflate(R.layout.fragment_home, container, false);
+
+ rvFeatured = view.findViewById(R.id.rvFeatured);
+ rvNearYou = view.findViewById(R.id.rvNearYou);
+
+ db = FirebaseFirestore.getInstance();
+
+ setupRecyclers();
+ loadRestaurants();
+
+ return view;
+ }
+
+ private void setupRecyclers() {
+ featuredAdapter = new RestaurantAdapter(featuredList, true, this::onRestaurantClick);
+ rvFeatured.setAdapter(featuredAdapter);
+ rvFeatured.setLayoutManager(new LinearLayoutManager(getContext(), LinearLayoutManager.HORIZONTAL, false));
+
+ nearYouAdapter = new RestaurantAdapter(nearYouList, false, this::onRestaurantClick);
+ rvNearYou.setAdapter(nearYouAdapter);
+ rvNearYou.setLayoutManager(new LinearLayoutManager(getContext()));
+ }
+
+ private void loadRestaurants() {
+ db.collection("restaurants").get().addOnCompleteListener(task -> {
+ if (task.isSuccessful()) {
+ featuredList.clear();
+ nearYouList.clear();
+ for (QueryDocumentSnapshot document : task.getResult()) {
+ Restaurant r = document.toObject(Restaurant.class);
+ r.setId(document.getId());
+ featuredList.add(r);
+ nearYouList.add(r);
+ }
+ featuredAdapter.notifyDataSetChanged();
+ nearYouAdapter.notifyDataSetChanged();
+ }
+ });
+ }
+
+ private void onRestaurantClick(Restaurant restaurant) {
+ Intent intent = new Intent(getActivity(), RestaurantDetailActivity.class);
+ intent.putExtra(RestaurantDetailActivity.EXTRA_RESTAURANT_ID, restaurant.getId());
+ intent.putExtra(RestaurantDetailActivity.EXTRA_RESTAURANT_NAME, restaurant.getName());
+ intent.putExtra(RestaurantDetailActivity.EXTRA_RESTAURANT_IMAGE, restaurant.getImageURL());
+ intent.putExtra(RestaurantDetailActivity.EXTRA_RESTAURANT_CUISINE, restaurant.getCuisine());
+ intent.putExtra(RestaurantDetailActivity.EXTRA_RESTAURANT_RATING, restaurant.getRating());
+ intent.putExtra(RestaurantDetailActivity.EXTRA_RESTAURANT_DESC, restaurant.getDescription());
+ intent.putExtra(RestaurantDetailActivity.EXTRA_RESTAURANT_ADDRESS, restaurant.getAddress());
+ startActivity(intent);
+ }
+}
diff --git a/app/src/main/java/com/example/pap_teste/ListaEsperaActivity.java b/app/src/main/java/com/example/pap_teste/ListaEsperaActivity.java
deleted file mode 100644
index 7915511..0000000
--- a/app/src/main/java/com/example/pap_teste/ListaEsperaActivity.java
+++ /dev/null
@@ -1,254 +0,0 @@
-package com.example.pap_teste;
-
-import android.os.Bundle;
-
-import androidx.activity.EdgeToEdge;
-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 android.widget.ArrayAdapter;
-import android.widget.ListView;
-import android.widget.TextView;
-import android.widget.Toast;
-
-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 ListaEsperaActivity extends AppCompatActivity {
-
- private final List reservasPendentes = new ArrayList<>();
- private ArrayAdapter adapter;
- private ListView listReservas;
- private TextView txtInfo, txtNotas, txtMensagem;
- private Button btnConfirmar, btnRecusar;
- private int selectedIndex = -1;
- private String restaurantEmail;
- private DatabaseReference databaseReference;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- EdgeToEdge.enable(this);
- setContentView(R.layout.activity_lista_espera);
- ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.listaEsperaRoot), (v, insets) -> {
- Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
- v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
- return insets;
- });
-
- restaurantEmail = getIntent().getStringExtra(MainActivity.EXTRA_EMAIL);
- if (restaurantEmail == null) {
- if (com.google.firebase.auth.FirebaseAuth.getInstance().getCurrentUser() != null) {
- restaurantEmail = com.google.firebase.auth.FirebaseAuth.getInstance().getCurrentUser().getEmail();
- } else {
- restaurantEmail = ""; // Avoid hardcoded sabor_arte so we don't accidentally load wrong data
- }
- }
-
- bindViews();
- setupList();
- setupActions();
- loadReservasPendentes();
- }
-
- private void bindViews() {
- listReservas = findViewById(R.id.listReservasP);
- txtInfo = findViewById(R.id.txtReservaInfoP);
- txtNotas = findViewById(R.id.txtReservaNotasP);
- txtMensagem = findViewById(R.id.txtMensagemReservaP);
- btnConfirmar = findViewById(R.id.btnConfirmarReservaP);
- btnRecusar = findViewById(R.id.btnRecusarReservaP);
-
- Button back = findViewById(R.id.btnVoltar);
- if (back != null) {
- back.setOnClickListener(v -> finish());
- }
- }
-
- private void setupList() {
- adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_activated_1);
- listReservas.setAdapter(adapter);
-
- listReservas.setOnItemClickListener((parent, view, position, id) -> {
- selectedIndex = position;
- mostrarDetalhe(reservasPendentes.get(position));
- });
- }
-
- private void setupActions() {
- btnConfirmar.setOnClickListener(v -> mostrarMesasDisponiveis());
- btnRecusar.setOnClickListener(v -> showRecusarDialog());
- }
-
- private void mostrarMesasDisponiveis() {
- if (selectedIndex < 0 || selectedIndex >= reservasPendentes.size()) {
- Toast.makeText(this, "Selecione uma reserva.", Toast.LENGTH_SHORT).show();
- return;
- }
- Reserva item = reservasPendentes.get(selectedIndex);
-
- DatabaseReference mesasRef = FirebaseDatabase.getInstance().getReference("Mesas");
- mesasRef.orderByChild("restauranteEmail").equalTo(restaurantEmail).addListenerForSingleValueEvent(new ValueEventListener() {
- @Override
- public void onDataChange(@androidx.annotation.NonNull DataSnapshot snapshot) {
- List mesasLivres = new ArrayList<>();
- for (DataSnapshot ds : snapshot.getChildren()) {
- com.example.pap_teste.models.Mesa m = ds.getValue(com.example.pap_teste.models.Mesa.class);
- if (m != null && m.getEstado() != null && m.getEstado().equalsIgnoreCase("Livre")) {
- // 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 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;
- }
-
- 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(ListaEsperaActivity.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 DatabaseError error) {
- Toast.makeText(ListaEsperaActivity.this, "Erro ao carregar mesas.", Toast.LENGTH_SHORT).show();
- }
- });
- }
-
- private void confirmarReservaComMesa(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()) {
- 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();
- selectedIndex = -1;
- toggleButtons(null);
- });
- } else {
- Toast.makeText(this, "Erro ao confirmar reserva.", Toast.LENGTH_SHORT).show();
- }
- });
- }
-
- private void showRecusarDialog() {
- if (selectedIndex < 0) return;
-
- String[] motivos = { "Sem espaço no restaurante", "Fora de horas", "Reserva duplicada", "Outro" };
- new androidx.appcompat.app.AlertDialog.Builder(this)
- .setTitle("Motivo da Recusa")
- .setItems(motivos, (dialog, which) -> {
- atualizarEstadoSelecionado("Recusada (" + motivos[which] + ")");
- })
- .setNegativeButton("Voltar", null)
- .show();
- }
-
- private void atualizarEstadoSelecionado(String novoEstado) {
- if (selectedIndex < 0 || selectedIndex >= reservasPendentes.size()) {
- Toast.makeText(this, "Selecione uma reserva para avaliar.", Toast.LENGTH_SHORT).show();
- return;
- }
-
- Reserva item = reservasPendentes.get(selectedIndex);
- databaseReference.child(item.getId()).child("estado").setValue(novoEstado).addOnCompleteListener(task -> {
- if (task.isSuccessful()) {
- Toast.makeText(this, "Reserva avaliada com sucesso.", Toast.LENGTH_SHORT).show();
- selectedIndex = -1;
- toggleButtons(null);
- } else {
- Toast.makeText(this, "Erro ao alterar estado da reserva.", Toast.LENGTH_SHORT).show();
- }
- });
- }
-
- private void mostrarDetalhe(Reserva item) {
- txtInfo.setText(String.format("%s • %s", item.getClienteEmail(), item.getHora()));
- txtNotas.setText(String.format("Data: %s • Pessoas: %d", item.getData(), item.getPessoas()));
- toggleButtons(item);
- }
-
- private void toggleButtons(Reserva item) {
- if (item == null) {
- btnConfirmar.setVisibility(android.view.View.GONE);
- btnRecusar.setVisibility(android.view.View.GONE);
- txtInfo.setText("Selecione uma reserva");
- txtNotas.setText("");
- return;
- }
- btnConfirmar.setVisibility(android.view.View.VISIBLE);
- btnRecusar.setVisibility(android.view.View.VISIBLE);
- }
-
- private void loadReservasPendentes() {
- databaseReference = FirebaseDatabase.getInstance().getReference("reservas");
- databaseReference.addValueEventListener(new ValueEventListener() {
- @Override
- public void onDataChange(@androidx.annotation.NonNull DataSnapshot snapshot) {
- reservasPendentes.clear();
- String targetEmail = restaurantEmail != null ? restaurantEmail.trim() : "";
- for (DataSnapshot data : snapshot.getChildren()) {
- Reserva r = data.getValue(Reserva.class);
- if (r != null && "Pendente".equals(r.getEstado())) {
- String rEmail = r.getRestauranteEmail();
- if (rEmail != null && rEmail.trim().equalsIgnoreCase(targetEmail)) {
- reservasPendentes.add(r);
- }
- }
- }
- refreshList();
- }
-
- @Override
- public void onCancelled(@androidx.annotation.NonNull DatabaseError error) {
- Toast.makeText(ListaEsperaActivity.this, "Erro ao carregar lista de espera.", Toast.LENGTH_SHORT).show();
- }
- });
- }
-
- private void refreshList() {
- adapter.clear();
- for (Reserva item : reservasPendentes) {
- adapter.add(String.format("%s - %dp • %s", item.getHora(), item.getPessoas(), item.getClienteEmail()));
- }
- adapter.notifyDataSetChanged();
- }
-}
-
-
-
-
-
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 9d77089..5573556 100644
--- a/app/src/main/java/com/example/pap_teste/MainActivity.java
+++ b/app/src/main/java/com/example/pap_teste/MainActivity.java
@@ -1,607 +1,112 @@
package com.example.pap_teste;
import android.content.Intent;
-import android.content.SharedPreferences;
-import android.graphics.Color;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
-import android.widget.Button;
-import android.widget.EditText;
import android.widget.Toast;
-
-import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
-import androidx.core.graphics.Insets;
-import androidx.core.view.ViewCompat;
-import androidx.core.view.WindowInsetsCompat;
-import androidx.core.content.ContextCompat;
-import androidx.appcompat.app.AlertDialog;
-import android.Manifest;
-import android.content.pm.PackageManager;
-import android.os.Build;
-import androidx.activity.result.ActivityResultLauncher;
-import androidx.activity.result.contract.ActivityResultContracts;
-
-import com.google.firebase.FirebaseApp;
+import com.example.pap_teste.models.User;
+import com.google.android.material.button.MaterialButton;
+import com.google.android.material.button.MaterialButtonToggleGroup;
+import com.google.android.material.textfield.TextInputEditText;
+import com.google.android.material.textfield.TextInputLayout;
import com.google.firebase.auth.FirebaseAuth;
-import com.google.firebase.database.DataSnapshot;
-import com.google.firebase.database.DatabaseReference;
-import com.google.firebase.database.FirebaseDatabase;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import com.google.firebase.firestore.FirebaseFirestore;
+import java.util.Date;
public class MainActivity extends AppCompatActivity {
- public static final String EXTRA_ACTION_MODE = "extra_action_mode";
- public static final String EXTRA_DISPLAY_NAME = "extra_display_name";
- public static final String EXTRA_EMAIL = "extra_email";
- public static final String EXTRA_ACCOUNT_TYPE = "extra_account_type";
- public static final String EXTRA_ROLE = "extra_role";
- private static final String PREFS_NAME = "pap_prefs";
- private static final String KEY_HAS_CREATED_ACCOUNT = "has_created_account";
+ private FirebaseAuth mAuth;
+ private FirebaseFirestore db;
+ private boolean isLoginMode = true;
- public enum AccountType {
- CLIENTE, ESTABELECIMENTO
- }
-
- public enum AccountAction {
- ENTRAR, CRIAR
- }
-
- private AccountType selectedAccountType = AccountType.CLIENTE;
- private AccountAction selectedAccountAction = AccountAction.ENTRAR;
-
- private Button btnCliente;
- private Button btnEstabelecimento;
- private Button btnEntrar;
- private Button btnCriarConta;
- private Button btnPrimaryAction;
- private EditText inputName;
- private EditText inputEmail;
- private EditText inputPassword;
- private EditText inputOwnerPhone;
- private EditText inputEstablishmentName;
- private EditText inputEstablishmentEmail;
- private EditText inputEstablishmentPhone;
- private android.widget.TextView txtForgotPassword;
- private android.widget.ImageView iconPasswordVisibility;
- private boolean isPasswordVisible = false;
- private boolean hasCreatedAccount;
- private FirebaseAuth firebaseAuth;
- private DatabaseReference databaseReference;
-
- private final ActivityResultLauncher permissionRequest = registerForActivityResult(
- new ActivityResultContracts.RequestMultiplePermissions(), result -> {
- Boolean fineLocationGranted = result.getOrDefault(Manifest.permission.ACCESS_FINE_LOCATION, false);
- Boolean bluetoothScanGranted = true;
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
- bluetoothScanGranted = result.getOrDefault(Manifest.permission.BLUETOOTH_SCAN, false);
- }
-
- if (fineLocationGranted != null && fineLocationGranted) {
- // Precise location access granted.
- } else {
- Toast.makeText(this, "A permissão de localização é necessária para o check-in.", Toast.LENGTH_LONG)
- .show();
- }
- });
+ private TextInputLayout layoutName;
+ private TextInputEditText inputName, inputEmail, inputPassword;
+ private MaterialButton btnPrimaryAction;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- EdgeToEdge.enable(this);
setContentView(R.layout.activity_main);
- ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
- Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
- v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
- return insets;
- });
- FirebaseApp.initializeApp(this);
- firebaseAuth = FirebaseAuth.getInstance();
- databaseReference = FirebaseDatabase.getInstance().getReference();
+ mAuth = FirebaseAuth.getInstance();
+ db = FirebaseFirestore.getInstance();
- bindViews();
- setupTypeToggle();
- setupActionToggle();
- setupPrimaryAction();
- checkPermissions();
- migrateUsersNodeToSeparateCollections();
+ // Check if user is already logged in
+ if (mAuth.getCurrentUser() != null) {
+ startActivity(new Intent(this, ClientDashboardActivity.class));
+ finish();
+ return;
+ }
+
+ initViews();
}
- private void migrateUsersNodeToSeparateCollections() {
- if (databaseReference == null) return;
- databaseReference.child("users").get().addOnCompleteListener(task -> {
- if (task.isSuccessful() && task.getResult() != null && task.getResult().exists()) {
- for (DataSnapshot userSnapshot : task.getResult().getChildren()) {
- String accountType = userSnapshot.child("accountType").getValue(String.class);
- String role = userSnapshot.child("role").getValue(String.class);
-
- String targetCollection = "Clientes";
- if ("ESTABELECIMENTO".equalsIgnoreCase(accountType) || "ADMIN".equalsIgnoreCase(role)) {
- targetCollection = "Restaurantes";
- }
-
- databaseReference.child(targetCollection).child(userSnapshot.getKey())
- .setValue(userSnapshot.getValue());
- }
- }
- });
- }
-
- private void checkPermissions() {
- List permissionsNeeded = new ArrayList<>();
- if (ContextCompat.checkSelfPermission(this,
- Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
- permissionsNeeded.add(Manifest.permission.ACCESS_FINE_LOCATION);
- }
-
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
- if (ContextCompat.checkSelfPermission(this,
- Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED) {
- permissionsNeeded.add(Manifest.permission.BLUETOOTH_SCAN);
- }
- if (ContextCompat.checkSelfPermission(this,
- Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
- permissionsNeeded.add(Manifest.permission.BLUETOOTH_CONNECT);
- }
- }
-
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
- if (ContextCompat.checkSelfPermission(this,
- Manifest.permission.READ_MEDIA_IMAGES) != PackageManager.PERMISSION_GRANTED) {
- permissionsNeeded.add(Manifest.permission.READ_MEDIA_IMAGES);
- }
- } else {
- if (ContextCompat.checkSelfPermission(this,
- Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
- permissionsNeeded.add(Manifest.permission.READ_EXTERNAL_STORAGE);
- }
- }
-
- if (!permissionsNeeded.isEmpty()) {
- new AlertDialog.Builder(this)
- .setTitle("Permissões Necessárias")
- .setMessage(
- "Para o correto funcionamento do check-in, serviços de proximidade e fotos da galeria, precisamos de algumas permissões.")
- .setPositiveButton("Configurar", (dialog, which) -> {
- permissionRequest.launch(permissionsNeeded.toArray(new String[0]));
- })
- .setNegativeButton("Agora Não", null)
- .show();
- }
- }
-
- private void bindViews() {
- btnCliente = findViewById(R.id.btnCliente);
- btnEstabelecimento = findViewById(R.id.btnEstabelecimento);
- btnEntrar = findViewById(R.id.btnEntrar);
- btnCriarConta = findViewById(R.id.btnCriarConta);
- btnPrimaryAction = findViewById(R.id.btnFinalCriarConta);
+ private void initViews() {
+ layoutName = findViewById(R.id.layoutName);
inputName = findViewById(R.id.inputName);
inputEmail = findViewById(R.id.inputEmail);
inputPassword = findViewById(R.id.inputPassword);
- inputOwnerPhone = findViewById(R.id.inputOwnerPhone);
- inputEstablishmentName = findViewById(R.id.inputEstablishmentName);
- inputEstablishmentEmail = findViewById(R.id.inputEstablishmentEmail);
- inputEstablishmentPhone = findViewById(R.id.inputEstablishmentPhone);
- txtForgotPassword = findViewById(R.id.txtForgotPassword);
- iconPasswordVisibility = findViewById(R.id.iconPasswordVisibility);
+ btnPrimaryAction = findViewById(R.id.btnPrimaryAction);
+ MaterialButtonToggleGroup toggleGroup = findViewById(R.id.toggleGroup);
- setupPasswordFeatures();
- }
-
- private void setupPasswordFeatures() {
- iconPasswordVisibility.setOnClickListener(v -> {
- isPasswordVisible = !isPasswordVisible;
- if (isPasswordVisible) {
- inputPassword.setInputType(android.text.InputType.TYPE_CLASS_TEXT
- | android.text.InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD);
- iconPasswordVisibility.setImageResource(R.drawable.ic_visibility);
- } else {
- inputPassword.setInputType(
- android.text.InputType.TYPE_CLASS_TEXT | android.text.InputType.TYPE_TEXT_VARIATION_PASSWORD);
- iconPasswordVisibility.setImageResource(R.drawable.ic_visibility_off);
+ toggleGroup.addOnButtonCheckedListener((group, checkedId, isChecked) -> {
+ if (isChecked) {
+ isLoginMode = checkedId == R.id.btnEntrar;
+ layoutName.setVisibility(isLoginMode ? View.GONE : View.VISIBLE);
+ btnPrimaryAction.setText(isLoginMode ? "Entrar" : "Criar Conta");
+ findViewById(R.id.txtForgotPassword).setVisibility(isLoginMode ? View.VISIBLE : View.GONE);
}
- inputPassword.setSelection(inputPassword.getText().length());
});
- txtForgotPassword.setOnClickListener(v -> {
+ btnPrimaryAction.setOnClickListener(v -> handleAuth());
+
+ findViewById(R.id.txtForgotPassword).setOnClickListener(v -> {
String email = inputEmail.getText().toString().trim();
if (TextUtils.isEmpty(email)) {
- Toast.makeText(this, "Por favor, introduza o seu email primeiro.", Toast.LENGTH_SHORT).show();
+ Toast.makeText(this, "Insira o seu email.", Toast.LENGTH_SHORT).show();
return;
}
-
- new AlertDialog.Builder(this)
- .setTitle("Recuperar palavra-passe")
- .setMessage("Deseja enviar um email de recuperação para " + email + "?")
- .setPositiveButton("Sim", (dialog, which) -> {
- if (firebaseAuth != null) {
- firebaseAuth.sendPasswordResetEmail(email)
- .addOnCompleteListener(task -> {
- if (task.isSuccessful()) {
- Toast.makeText(MainActivity.this, "Email de recuperação enviado!",
- Toast.LENGTH_LONG).show();
- } else {
- Toast.makeText(MainActivity.this,
- "Falha ao enviar email. Verifique se o endereço está correto.",
- Toast.LENGTH_LONG).show();
- }
- });
- }
- })
- .setNegativeButton("Não", null)
- .show();
+ mAuth.sendPasswordResetEmail(email).addOnSuccessListener(aVoid ->
+ Toast.makeText(this, "Email de recuperação enviado.", Toast.LENGTH_SHORT).show());
});
}
- private void setupTypeToggle() {
- btnCliente.setOnClickListener(v -> {
- selectedAccountType = AccountType.CLIENTE;
- updateTypeButtons();
- });
- btnEstabelecimento.setOnClickListener(v -> {
- selectedAccountType = AccountType.ESTABELECIMENTO;
- updateTypeButtons();
- });
- updateTypeButtons();
- }
-
- private void setupActionToggle() {
- btnEntrar.setOnClickListener(v -> {
- selectedAccountAction = AccountAction.ENTRAR;
- updateActionButtons();
- });
- btnCriarConta.setOnClickListener(v -> {
- selectedAccountAction = AccountAction.CRIAR;
- updateActionButtons();
- });
- updateActionButtons();
- }
-
- private void setupPrimaryAction() {
- btnPrimaryAction.setOnClickListener(v -> handlePrimaryAction());
- updatePrimaryActionState();
- }
-
- private void updateTypeButtons() {
- setSelectedState(btnCliente, selectedAccountType == AccountType.CLIENTE);
- setSelectedState(btnEstabelecimento, selectedAccountType == AccountType.ESTABELECIMENTO);
- updateInputVisibility();
- }
-
- private void updateActionButtons() {
- setSelectedState(btnEntrar, selectedAccountAction == AccountAction.ENTRAR);
- setSelectedState(btnCriarConta, selectedAccountAction == AccountAction.CRIAR);
- updatePrimaryActionState();
- }
-
- private void setSelectedState(Button button, boolean isSelected) {
- int selectedTextColor = Color.WHITE;
- int defaultTextColor = Color.parseColor("#231F1F");
- button.setBackgroundResource(isSelected ? R.drawable.tab_selected : R.drawable.tab_unselected);
- button.setTextColor(isSelected ? selectedTextColor : defaultTextColor);
- }
-
- private void updatePrimaryActionState() {
- boolean creatingAccount = selectedAccountAction == AccountAction.CRIAR;
- btnPrimaryAction.setText(creatingAccount ? "Criar Conta" : "Entrar");
- updateInputVisibility();
- }
-
- private void updateInputVisibility() {
- boolean creatingAccount = selectedAccountAction == AccountAction.CRIAR;
- boolean isEstablishment = selectedAccountType == AccountType.ESTABELECIMENTO;
-
- inputName.setHint(isEstablishment ? "Nome do proprietário" : "O seu nome");
- inputEmail.setHint(isEstablishment ? "Email do proprietário" : "Email");
-
- inputName.setVisibility(creatingAccount ? View.VISIBLE : View.GONE);
- inputOwnerPhone.setVisibility(creatingAccount && isEstablishment ? View.VISIBLE : View.GONE);
- inputEstablishmentName.setVisibility(creatingAccount && isEstablishment ? View.VISIBLE : View.GONE);
- inputEstablishmentEmail.setVisibility(creatingAccount && isEstablishment ? View.VISIBLE : View.GONE);
- inputEstablishmentPhone.setVisibility(creatingAccount && isEstablishment ? View.VISIBLE : View.GONE);
-
- if (txtForgotPassword != null) {
- txtForgotPassword.setVisibility(creatingAccount ? View.GONE : View.VISIBLE);
- }
- }
-
- private void handlePrimaryAction() {
+ private void handleAuth() {
String email = inputEmail.getText().toString().trim();
String password = inputPassword.getText().toString().trim();
- String providedName = inputName.getText().toString().trim();
- String ownerPhone = inputOwnerPhone.getText().toString().trim();
- String establishmentName = inputEstablishmentName.getText().toString().trim();
- String establishmentEmail = inputEstablishmentEmail.getText().toString().trim();
- String establishmentPhone = inputEstablishmentPhone.getText().toString().trim();
+ String name = inputName.getText().toString().trim();
if (TextUtils.isEmpty(email) || TextUtils.isEmpty(password)) {
- Toast.makeText(this, "Preencha email e palavra-passe.", Toast.LENGTH_SHORT).show();
+ Toast.makeText(this, "Preencha todos os campos.", Toast.LENGTH_SHORT).show();
return;
}
- boolean creatingAccount = selectedAccountAction == AccountAction.CRIAR;
-
- if (creatingAccount && !isValidPassword(password)) {
- return;
- }
-
- if (creatingAccount) {
- if (selectedAccountType == AccountType.CLIENTE && TextUtils.isEmpty(providedName)) {
- Toast.makeText(this, "Indique o seu nome para criar conta.", Toast.LENGTH_SHORT).show();
+ if (isLoginMode) {
+ mAuth.signInWithEmailAndPassword(email, password)
+ .addOnSuccessListener(authResult -> {
+ startActivity(new Intent(this, ClientDashboardActivity.class));
+ finish();
+ })
+ .addOnFailureListener(e -> Toast.makeText(this, "Erro ao entrar: " + e.getMessage(), Toast.LENGTH_SHORT).show());
+ } else {
+ if (TextUtils.isEmpty(name)) {
+ Toast.makeText(this, "Insira o seu nome.", Toast.LENGTH_SHORT).show();
return;
}
-
- if (selectedAccountType == AccountType.ESTABELECIMENTO) {
- boolean missingOwner = TextUtils.isEmpty(providedName) || TextUtils.isEmpty(ownerPhone);
- boolean missingEstablishment = TextUtils.isEmpty(establishmentName)
- || TextUtils.isEmpty(establishmentEmail)
- || TextUtils.isEmpty(establishmentPhone);
-
- if (missingOwner || missingEstablishment) {
- Toast.makeText(this, "Preencha os dados do proprietário e do estabelecimento.", Toast.LENGTH_SHORT)
- .show();
- return;
- }
- }
+ mAuth.createUserWithEmailAndPassword(email, password)
+ .addOnSuccessListener(authResult -> {
+ String uid = authResult.getUser().getUid();
+ User newUser = new User(uid, name, email, "CLIENTE");
+ db.collection("users").document(uid).set(newUser)
+ .addOnSuccessListener(aVoid -> {
+ startActivity(new Intent(this, ClientDashboardActivity.class));
+ finish();
+ });
+ })
+ .addOnFailureListener(e -> Toast.makeText(this, "Erro ao registar: " + e.getMessage(), Toast.LENGTH_SHORT).show());
}
-
- String fallbackName = !TextUtils.isEmpty(providedName) ? providedName : deriveNameFromEmail(email);
- String resolvedRole = getRoleForSelectedType();
-
- if (creatingAccount) {
- createAccountInFirebase(
- email,
- password,
- providedName,
- ownerPhone,
- establishmentName,
- establishmentEmail,
- establishmentPhone,
- fallbackName,
- resolvedRole);
- return;
- }
-
- signInExistingAccount(email, password, fallbackName, resolvedRole);
}
+}
- private String deriveNameFromEmail(String email) {
- if (!email.contains("@")) {
- return "Utilizador";
- }
- String candidate = email.substring(0, email.indexOf("@"));
- if (candidate.isEmpty()) {
- return "Utilizador";
- }
- String firstLetter = candidate.substring(0, 1).toUpperCase();
- String rest = candidate.length() > 1 ? candidate.substring(1) : "";
- return firstLetter + rest;
- }
-
- private void markAccountCreated() {
- hasCreatedAccount = true;
- SharedPreferences prefs = getSharedPreferences(PREFS_NAME, MODE_PRIVATE);
- prefs.edit().putBoolean(KEY_HAS_CREATED_ACCOUNT, true).apply();
- }
-
- private String getRoleForSelectedType() {
- return selectedAccountType == AccountType.ESTABELECIMENTO ? "ADMIN" : "CLIENTE";
- }
-
- private String buildDocumentId(String email) {
- return email.replace(".", "_").replace("@", "_at_");
- }
-
- private boolean ensureFirebaseReady() {
- boolean ready = firebaseAuth != null && databaseReference != null;
- if (!ready) {
- Toast.makeText(this, "Ligue-se ao Firebase para continuar.", Toast.LENGTH_SHORT).show();
- }
- return ready;
- }
-
- private void signInExistingAccount(String email, String password, String fallbackName, String resolvedRole) {
- if (!ensureFirebaseReady()) {
- return;
- }
-
- firebaseAuth.signInWithEmailAndPassword(email, password)
- .addOnSuccessListener(authResult -> fetchAccountAndNavigate(email, fallbackName, resolvedRole))
- .addOnFailureListener(e -> {
- android.util.Log.e("LoginError", "SignIn failed", e);
- Toast.makeText(this, "Não foi possível iniciar sessão: " + e.getMessage(), Toast.LENGTH_SHORT)
- .show();
- });
- }
-
- private void createAccountInFirebase(
- String email,
- String password,
- String providedName,
- String ownerPhone,
- String establishmentName,
- String establishmentEmail,
- String establishmentPhone,
- String fallbackName,
- String resolvedRole) {
- if (!ensureFirebaseReady()) {
- return;
- }
-
- firebaseAuth.createUserWithEmailAndPassword(email, password)
- .addOnSuccessListener(result -> {
- if (!hasCreatedAccount) {
- markAccountCreated();
- }
- String finalDisplayName = selectedAccountType == AccountType.ESTABELECIMENTO
- && !TextUtils.isEmpty(establishmentName)
- ? establishmentName
- : fallbackName;
- String uid = result.getUser() != null ? result.getUser().getUid() : null;
-
- persistAccountInFirebase(
- email,
- providedName,
- resolvedRole,
- ownerPhone,
- establishmentName,
- establishmentEmail,
- establishmentPhone,
- uid,
- () -> {
- Toast.makeText(this, "Conta criada com sucesso! Carregue em Entrar.", Toast.LENGTH_LONG)
- .show();
- selectedAccountAction = AccountAction.ENTRAR;
- updateActionButtons();
- });
- })
- .addOnFailureListener(e -> {
- android.util.Log.e("LoginError", "CreateUser failed", e);
- Toast.makeText(this, "Falha ao criar conta: " + e.getMessage(), Toast.LENGTH_SHORT).show();
- });
- }
-
- private void fetchAccountAndNavigate(String email, String fallbackName, String resolvedRole) {
- if (databaseReference == null) {
- Toast.makeText(this, "Firebase indisponível.", Toast.LENGTH_SHORT).show();
- if (firebaseAuth != null) firebaseAuth.signOut();
- return;
- }
-
- String documentId = buildDocumentId(email);
- String collectionPath = selectedAccountType == AccountType.ESTABELECIMENTO ? "Restaurantes" : "Clientes";
- databaseReference.child(collectionPath).child(documentId).get().addOnCompleteListener(task -> {
- if (!task.isSuccessful()) {
- android.util.Log.e("LoginError", "Database check failed", task.getException());
- Toast.makeText(this, "Falha ao validar perfil. Tente novamente.", Toast.LENGTH_SHORT)
- .show();
- if (firebaseAuth != null) firebaseAuth.signOut();
- return;
- }
-
- DataSnapshot snapshot = task.getResult();
- if (snapshot == null || !snapshot.exists()) {
- String tipo = selectedAccountType == AccountType.ESTABELECIMENTO ? "Estabelecimento" : "Cliente";
- Toast.makeText(this, "Conta não encontrada como " + tipo + ".\nPor favor, crie uma conta nova.", Toast.LENGTH_LONG).show();
- if (firebaseAuth != null) firebaseAuth.signOut();
- return;
- }
-
- String accountTypeInFirebase = snapshot.child("accountType").getValue(String.class);
- if (accountTypeInFirebase != null
- && !accountTypeInFirebase.equalsIgnoreCase(selectedAccountType.name())) {
- Toast.makeText(this, "Tipo de conta não corresponde ao registo.\nPor favor verifique se escolheu a opção correta.", Toast.LENGTH_LONG)
- .show();
- if (firebaseAuth != null) firebaseAuth.signOut();
- return;
- }
-
- String displayNameFromDb = snapshot.child("displayName").getValue(String.class);
- String establishmentName = snapshot.child("establishmentName").getValue(String.class);
- String ownerName = snapshot.child("ownerName").getValue(String.class);
- String roleFromDb = snapshot.child("role").getValue(String.class);
-
- String finalDisplayName = !TextUtils.isEmpty(establishmentName)
- ? establishmentName
- : !TextUtils.isEmpty(displayNameFromDb) ? displayNameFromDb
- : !TextUtils.isEmpty(ownerName) ? ownerName
- : fallbackName;
-
- String finalRole = !TextUtils.isEmpty(roleFromDb) ? roleFromDb : resolvedRole;
- navigateToDashboard(email, finalDisplayName, finalRole);
- });
- }
-
- private void navigateToDashboard(String email, String displayName, String role) {
- Intent nextScreen = selectedAccountType == AccountType.CLIENTE
- ? new Intent(this, ClientDashboardActivity.class)
- : new Intent(this, EstablishmentDashboardActivity.class);
-
- nextScreen.putExtra(EXTRA_ACTION_MODE, selectedAccountAction.name());
- nextScreen.putExtra(EXTRA_DISPLAY_NAME, displayName);
- nextScreen.putExtra(EXTRA_EMAIL, email);
- nextScreen.putExtra(EXTRA_ACCOUNT_TYPE, selectedAccountType.name());
- nextScreen.putExtra(EXTRA_ROLE, role);
- startActivity(nextScreen);
- }
-
- private void persistAccountInFirebase(
- String ownerEmail,
- String ownerName,
- String role,
- String ownerPhone,
- String establishmentName,
- String establishmentEmail,
- String establishmentPhone,
- String uid,
- Runnable onSuccess) {
- if (databaseReference == null) {
- Toast.makeText(this, "Firebase indisponível.", Toast.LENGTH_SHORT).show();
- return;
- }
-
- String documentId = buildDocumentId(ownerEmail);
- Map payload = new HashMap<>();
- if (!TextUtils.isEmpty(uid)) {
- payload.put("uid", uid);
- }
- payload.put("email", ownerEmail);
- payload.put("displayName", ownerName);
- payload.put("role", role);
- payload.put("accountType", selectedAccountType.name());
- payload.put("createdAt", System.currentTimeMillis());
-
- if (selectedAccountType == AccountType.ESTABELECIMENTO) {
- payload.put("ownerName", ownerName);
- payload.put("ownerEmail", ownerEmail);
- payload.put("ownerPhone", ownerPhone);
- payload.put("establishmentName", establishmentName);
- payload.put("establishmentEmail", establishmentEmail);
- payload.put("establishmentPhone", establishmentPhone);
- }
-
- String collectionPath = selectedAccountType == AccountType.ESTABELECIMENTO ? "Restaurantes" : "Clientes";
- databaseReference.child(collectionPath).child(documentId).updateChildren(payload)
- .addOnSuccessListener(unused -> {
- Toast.makeText(this, "Conta guardada na cloud.", Toast.LENGTH_SHORT).show();
- if (onSuccess != null) {
- onSuccess.run();
- }
- })
- .addOnFailureListener(
- e -> Toast.makeText(this, "Não foi possível guardar na cloud.", Toast.LENGTH_SHORT).show());
- }
-
- private boolean isValidPassword(String password) {
- if (password.length() < 6) {
- Toast.makeText(this, "A palavra-passe deve ter pelo menos 6 caracteres.", Toast.LENGTH_SHORT).show();
- return false;
- }
- boolean hasLower = false;
- boolean hasDigit = false;
- boolean hasSpecial = false;
-
- for (char c : password.toCharArray()) {
- if (Character.isLowerCase(c))
- hasLower = true;
- else if (Character.isDigit(c))
- hasDigit = true;
- else if (!Character.isLetterOrDigit(c))
- hasSpecial = true;
- }
-
- if (!hasLower || !hasDigit || !hasSpecial) {
- Toast.makeText(this, "A palavra-passe deve conter minúsculas, números e símbolos.", Toast.LENGTH_LONG)
- .show();
- return false;
- }
- return true;
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/pap_teste/MyReservationsFragment.java b/app/src/main/java/com/example/pap_teste/MyReservationsFragment.java
new file mode 100644
index 0000000..8a5c5f2
--- /dev/null
+++ b/app/src/main/java/com/example/pap_teste/MyReservationsFragment.java
@@ -0,0 +1,98 @@
+package com.example.pap_teste;
+
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ProgressBar;
+import android.widget.Toast;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
+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 java.util.ArrayList;
+import java.util.List;
+
+public class MyReservationsFragment extends Fragment {
+
+ private RecyclerView rvReservations;
+ private ReservaAdapter adapter;
+ private List reservationList = new ArrayList<>();
+ private ProgressBar progressBar;
+ private View emptyState;
+ private FirebaseFirestore db;
+
+ @Nullable
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ View view = inflater.inflate(R.layout.fragment_my_reservations, container, false);
+
+ rvReservations = view.findViewById(R.id.rvReservations);
+ progressBar = view.findViewById(R.id.progressBar);
+ emptyState = view.findViewById(R.id.emptyState);
+
+ db = FirebaseFirestore.getInstance();
+
+ setupAdapter();
+ loadReservations();
+
+ return view;
+ }
+
+ private void setupAdapter() {
+ adapter = new ReservaAdapter(reservationList, new ReservaAdapter.OnReservaActionListener() {
+ @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();
+ }
+
+ @Override
+ public void onCancel(Reserva reserva) {
+ cancelReservation(reserva);
+ }
+ });
+ rvReservations.setAdapter(adapter);
+ }
+
+ private void loadReservations() {
+ String userId = FirebaseAuth.getInstance().getUid();
+ if (userId == null) return;
+
+ 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());
+ }
+}
diff --git a/app/src/main/java/com/example/pap_teste/OnboardingActivity.java b/app/src/main/java/com/example/pap_teste/OnboardingActivity.java
new file mode 100644
index 0000000..387401c
--- /dev/null
+++ b/app/src/main/java/com/example/pap_teste/OnboardingActivity.java
@@ -0,0 +1,46 @@
+package com.example.pap_teste;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.animation.AlphaAnimation;
+import android.view.animation.Animation;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.activity.EdgeToEdge;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.core.graphics.Insets;
+import androidx.core.view.ViewCompat;
+import androidx.core.view.WindowInsetsCompat;
+
+import com.google.android.material.button.MaterialButton;
+
+public class OnboardingActivity extends AppCompatActivity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ EdgeToEdge.enable(this);
+ setContentView(R.layout.activity_onboarding);
+ ViewCompat.setOnApplyWindowInsetsListener(findViewById(android.R.id.content), (v, insets) -> {
+ Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
+ v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
+ return insets;
+ });
+
+ ImageView logo = findViewById(R.id.logo);
+ TextView tagline = findViewById(R.id.tagline);
+ MaterialButton btnGetStarted = findViewById(R.id.btnGetStarted);
+
+ // Simple animation
+ Animation fadeIn = new AlphaAnimation(0, 1);
+ fadeIn.setDuration(1500);
+ logo.startAnimation(fadeIn);
+ tagline.startAnimation(fadeIn);
+
+ btnGetStarted.setOnClickListener(v -> {
+ startActivity(new Intent(OnboardingActivity.this, MainActivity.class));
+ 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
new file mode 100644
index 0000000..7a4ee69
--- /dev/null
+++ b/app/src/main/java/com/example/pap_teste/ProfileFragment.java
@@ -0,0 +1,55 @@
+package com.example.pap_teste;
+
+import android.content.Intent;
+import android.os.Bundle;
+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.annotation.Nullable;
+import androidx.fragment.app.Fragment;
+import com.bumptech.glide.Glide;
+import com.google.firebase.auth.FirebaseAuth;
+import com.google.firebase.auth.FirebaseUser;
+
+public class ProfileFragment extends Fragment {
+
+ private ImageView imgProfile;
+ private TextView txtName, txtEmail;
+
+ @Nullable
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ View view = inflater.inflate(R.layout.fragment_profile, container, false);
+
+ imgProfile = view.findViewById(R.id.imgProfile);
+ txtName = view.findViewById(R.id.txtProfileName);
+ txtEmail = view.findViewById(R.id.txtProfileEmail);
+
+ FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
+ if (user != null) {
+ txtName.setText(user.getDisplayName() != null ? user.getDisplayName() : "Utilizador");
+ txtEmail.setText(user.getEmail());
+
+ if (user.getPhotoUrl() != null) {
+ Glide.with(this).load(user.getPhotoUrl()).circleCrop().into(imgProfile);
+ }
+ }
+
+ view.findViewById(R.id.btnSeedData).setOnClickListener(v -> {
+ DataSeeder.seedRestaurants();
+ Toast.makeText(getContext(), "Dados semeados com sucesso!", Toast.LENGTH_SHORT).show();
+ });
+
+ view.findViewById(R.id.btnLogout).setOnClickListener(v -> {
+ FirebaseAuth.getInstance().signOut();
+ Intent intent = new Intent(getActivity(), MainActivity.class);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ startActivity(intent);
+ });
+
+ return view;
+ }
+}
diff --git a/app/src/main/java/com/example/pap_teste/ReservaAdapter.java b/app/src/main/java/com/example/pap_teste/ReservaAdapter.java
index 4c0ad77..625abda 100644
--- a/app/src/main/java/com/example/pap_teste/ReservaAdapter.java
+++ b/app/src/main/java/com/example/pap_teste/ReservaAdapter.java
@@ -5,24 +5,24 @@ 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 com.google.android.material.chip.Chip;
+import java.text.SimpleDateFormat;
import java.util.List;
+import java.util.Locale;
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;
+ private final SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy", Locale.getDefault());
public ReservaAdapter(List reservas, OnReservaActionListener listener) {
this.reservas = reservas;
@@ -39,64 +39,40 @@ public class ReservaAdapter extends RecyclerView.Adapter {
- if (listener != null)
- listener.onCheckIn(reserva);
- });
-
- holder.btnCancelar.setOnClickListener(v -> {
- if (listener != null)
- listener.onCancel(reserva);
- });
+ holder.btnCheckIn.setOnClickListener(v -> listener.onCheckIn(reserva));
+ holder.btnCancelar.setOnClickListener(v -> listener.onCancel(reserva));
}
@Override
@@ -105,19 +81,18 @@ public class ReservaAdapter extends RecyclerView.Adapter timeSlots = new ArrayList<>();
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_reservation);
+
+ restaurantId = getIntent().getStringExtra(RestaurantDetailActivity.EXTRA_RESTAURANT_ID);
+ restaurantName = getIntent().getStringExtra(RestaurantDetailActivity.EXTRA_RESTAURANT_NAME);
+
+ Toolbar toolbar = findViewById(R.id.toolbar);
+ setSupportActionBar(toolbar);
+ if (getSupportActionBar() != null) {
+ getSupportActionBar().setDisplayHomeAsUpEnabled(true);
+ getSupportActionBar().setTitle("Reservar: " + restaurantName);
+ }
+
+ txtGuestCount = findViewById(R.id.txtGuestCount);
+ txtSelectedDate = findViewById(R.id.txtSelectedDate);
+ rvTimeSlots = findViewById(R.id.rvTimeSlots);
+ EditText etSpecialRequests = findViewById(R.id.etSpecialRequests);
+
+ findViewById(R.id.btnDecreaseGuests).setOnClickListener(v -> {
+ if (guestCount > 1) {
+ guestCount--;
+ txtGuestCount.setText(String.valueOf(guestCount));
+ }
+ });
+
+ findViewById(R.id.btnIncreaseGuests).setOnClickListener(v -> {
+ guestCount++;
+ txtGuestCount.setText(String.valueOf(guestCount));
+ });
+
+ findViewById(R.id.cardDatePicker).setOnClickListener(v -> showDatePicker());
+
+ setupTimeSlots();
+ loadRestaurantSlots();
+
+ findViewById(R.id.btnConfirmReservation).setOnClickListener(v -> {
+ if (selectedTimeSlot == null) {
+ Toast.makeText(this, "Por favor, selecione um horário.", Toast.LENGTH_SHORT).show();
+ return;
+ }
+ confirmReservation(etSpecialRequests.getText().toString());
+ });
+
+ toolbar.setNavigationOnClickListener(v -> onBackPressed());
+ }
+
+ private void showDatePicker() {
+ new DatePickerDialog(this, (view, year, month, dayOfMonth) -> {
+ selectedDate.set(year, month, dayOfMonth);
+ txtSelectedDate.setText(String.format("%02d/%02d/%d", dayOfMonth, month + 1, year));
+ }, selectedDate.get(Calendar.YEAR), selectedDate.get(Calendar.MONTH), selectedDate.get(Calendar.DAY_OF_MONTH)).show();
+ }
+
+ private void setupTimeSlots() {
+ adapter = new TimeSlotAdapter(timeSlots, slot -> selectedTimeSlot = slot);
+ rvTimeSlots.setAdapter(adapter);
+ rvTimeSlots.setLayoutManager(new GridLayoutManager(this, 3));
+ }
+
+ private void loadRestaurantSlots() {
+ // In a real app, we would fetch from Firestore based on the selected date
+ // For now, let's use the static slots from the restaurant model
+ FirebaseFirestore.getInstance().collection("restaurants").document(restaurantId).get()
+ .addOnSuccessListener(documentSnapshot -> {
+ Restaurant r = documentSnapshot.toObject(Restaurant.class);
+ if (r != null && r.getAvailableSlots() != null) {
+ timeSlots.clear();
+ timeSlots.addAll(r.getAvailableSlots());
+ adapter.notifyDataSetChanged();
+ }
+ });
+ }
+
+ private void confirmReservation(String specialRequests) {
+ String userId = FirebaseAuth.getInstance().getUid();
+ if (userId == null) {
+ Toast.makeText(this, "Erro de autenticação.", Toast.LENGTH_SHORT).show();
+ return;
+ }
+
+ Reserva reserva = new Reserva();
+ reserva.setUserId(userId);
+ reserva.setRestaurantId(restaurantId);
+ reserva.setRestaurantName(restaurantName);
+ reserva.setGuests(guestCount);
+ reserva.setDate(new Timestamp(selectedDate.getTime()));
+ reserva.setTimeSlot(selectedTimeSlot);
+ reserva.setSpecialRequests(specialRequests);
+ reserva.setStatus("confirmed");
+ reserva.setCreatedAt(new Timestamp(new Date()));
+
+ FirebaseFirestore.getInstance().collection("reservations").add(reserva)
+ .addOnSuccessListener(documentReference -> {
+ Toast.makeText(this, "Reserva confirmada com sucesso!", Toast.LENGTH_LONG).show();
+ finish();
+ })
+ .addOnFailureListener(e -> Toast.makeText(this, "Erro ao confirmar reserva.", Toast.LENGTH_SHORT).show());
+ }
+}
diff --git a/app/src/main/java/com/example/pap_teste/RestaurantAdapter.java b/app/src/main/java/com/example/pap_teste/RestaurantAdapter.java
index b384154..9416c72 100644
--- a/app/src/main/java/com/example/pap_teste/RestaurantAdapter.java
+++ b/app/src/main/java/com/example/pap_teste/RestaurantAdapter.java
@@ -3,132 +3,54 @@ package com.example.pap_teste;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.Button;
-import android.widget.ImageButton;
+import android.widget.ImageView;
import android.widget.TextView;
-
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
-
+import com.bumptech.glide.Glide;
import com.example.pap_teste.models.Restaurant;
-import com.google.firebase.auth.FirebaseAuth;
-import com.google.firebase.auth.FirebaseUser;
-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.List;
public class RestaurantAdapter extends RecyclerView.Adapter {
- private List restaurants;
- private OnRestaurantClickListener listener;
+
+ private final List restaurants;
+ private final boolean isFeatured;
+ private final OnRestaurantClickListener listener;
public interface OnRestaurantClickListener {
void onRestaurantClick(Restaurant restaurant);
}
public RestaurantAdapter(List restaurants, OnRestaurantClickListener listener) {
+ this(restaurants, false, listener);
+ }
+
+ public RestaurantAdapter(List restaurants, boolean isFeatured, OnRestaurantClickListener listener) {
this.restaurants = restaurants;
+ this.isFeatured = isFeatured;
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);
+ int layoutId = isFeatured ? R.layout.item_restaurant_featured : R.layout.item_restaurant_card;
+ View view = LayoutInflater.from(parent.getContext()).inflate(layoutId, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
Restaurant restaurant = restaurants.get(position);
- holder.text1.setText(restaurant.getName());
- holder.text2
- .setText(restaurant.getCategory() + (restaurant.isAvailable() ? " - Disponível" : " - Indisponível"));
+ holder.name.setText(restaurant.getName());
+ holder.cuisine.setText(String.format("%s • %.1f ★", restaurant.getCuisine(), restaurant.getRating()));
+
+ Glide.with(holder.itemView.getContext())
+ .load(restaurant.getImageURL())
+ .placeholder(R.drawable.na_mesa)
+ .into(holder.image);
- if (holder.txtRating != null) {
- if (restaurant.getRatingAvg() != null && restaurant.getRatingAvg() > 0) {
- holder.txtRating
- .setText(String.format(java.util.Locale.getDefault(), "%.1f", restaurant.getRatingAvg()));
- } else {
- holder.txtRating.setText("Novo");
- }
- }
-
- if (restaurant.getLogoUrl() != null && !restaurant.getLogoUrl().isEmpty()) {
- com.bumptech.glide.Glide.with(holder.itemView.getContext())
- .load(restaurant.getLogoUrl())
- .circleCrop()
- .into(holder.imgThumb);
- } else {
- holder.imgThumb.setImageResource(R.mipmap.ic_launcher);
- }
-
- holder.itemView.setOnClickListener(v -> {
- if (listener != null) {
- listener.onRestaurantClick(restaurant);
- }
- });
-
- if (holder.btnReservar != null) {
- holder.btnReservar.setOnClickListener(v -> {
- if (listener != null) {
- listener.onRestaurantClick(restaurant);
- }
- });
- }
-
- FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
- if (user != null && user.getEmail() != null && restaurant.getEmail() != null) {
- String encodedUserEmail = user.getEmail().replace(".", "_").replace("@", "_at_");
- String encodedRestEmail = restaurant.getEmail().replace(".", "_").replace("@", "_at_");
- DatabaseReference favRef = FirebaseDatabase.getInstance().getReference("Clientes")
- .child(encodedUserEmail).child("favorites").child(encodedRestEmail);
-
- // Read initial state
- favRef.addListenerForSingleValueEvent(new ValueEventListener() {
- @Override
- public void onDataChange(@NonNull DataSnapshot snapshot) {
- holder.btnFavorite.setTag(snapshot.exists());
- if (snapshot.exists()) {
- holder.btnFavorite.setImageResource(android.R.drawable.btn_star_big_on);
- holder.btnFavorite.setColorFilter(androidx.core.content.ContextCompat
- .getColor(holder.itemView.getContext(), R.color.colorPrimary));
- } else {
- holder.btnFavorite.setImageResource(android.R.drawable.btn_star_big_off);
- holder.btnFavorite.clearColorFilter();
- }
- }
-
- @Override
- public void onCancelled(@NonNull DatabaseError error) {
- }
- });
-
- holder.btnFavorite.setOnClickListener(v -> {
- // Optimistic UI update
- boolean isFav = holder.btnFavorite.getTag() != null && (Boolean) holder.btnFavorite.getTag();
- boolean newFavState = !isFav;
- holder.btnFavorite.setTag(newFavState);
-
- if (newFavState) {
- holder.btnFavorite.setImageResource(android.R.drawable.btn_star_big_on);
- holder.btnFavorite.setColorFilter(androidx.core.content.ContextCompat
- .getColor(holder.itemView.getContext(), R.color.colorPrimary));
- favRef.setValue(restaurant);
- com.google.android.material.snackbar.Snackbar.make(v, "Adicionado aos Favoritos!",
- com.google.android.material.snackbar.Snackbar.LENGTH_SHORT).show();
- } else {
- holder.btnFavorite.setImageResource(android.R.drawable.btn_star_big_off);
- holder.btnFavorite.clearColorFilter();
- favRef.removeValue();
- com.google.android.material.snackbar.Snackbar.make(v, "Removido dos Favoritos.",
- com.google.android.material.snackbar.Snackbar.LENGTH_SHORT).show();
- }
- });
- }
+ holder.itemView.setOnClickListener(v -> listener.onRestaurantClick(restaurant));
}
@Override
@@ -136,20 +58,16 @@ public class RestaurantAdapter extends RecyclerView.Adapter {
+ Intent intent = new Intent(this, ReservationActivity.class);
+ intent.putExtra(EXTRA_RESTAURANT_ID, getIntent().getStringExtra(EXTRA_RESTAURANT_ID));
+ intent.putExtra(EXTRA_RESTAURANT_NAME, getIntent().getStringExtra(EXTRA_RESTAURANT_NAME));
+ startActivity(intent);
+ });
+
+ toolbar.setNavigationOnClickListener(v -> onBackPressed());
+ }
+}
diff --git a/app/src/main/java/com/example/pap_teste/TimeSlotAdapter.java b/app/src/main/java/com/example/pap_teste/TimeSlotAdapter.java
new file mode 100644
index 0000000..bcdf153
--- /dev/null
+++ b/app/src/main/java/com/example/pap_teste/TimeSlotAdapter.java
@@ -0,0 +1,76 @@
+package com.example.pap_teste;
+
+import android.graphics.Color;
+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.google.android.material.card.MaterialCardView;
+import java.util.List;
+
+public class TimeSlotAdapter extends RecyclerView.Adapter {
+
+ private final List timeSlots;
+ private final OnTimeSlotClickListener listener;
+ private int selectedPosition = -1;
+
+ public interface OnTimeSlotClickListener {
+ void onTimeSlotClick(String slot);
+ }
+
+ public TimeSlotAdapter(List timeSlots, OnTimeSlotClickListener listener) {
+ this.timeSlots = timeSlots;
+ this.listener = listener;
+ }
+
+ @NonNull
+ @Override
+ public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_time_slot, parent, false);
+ return new ViewHolder(view);
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
+ String slot = timeSlots.get(position);
+ holder.txtTime.setText(slot);
+
+ boolean isSelected = selectedPosition == position;
+ holder.card.setStrokeColor(isSelected ? holder.itemView.getContext().getColor(R.color.colorPrimary) : holder.itemView.getContext().getColor(R.color.colorBorder));
+ holder.card.setStrokeWidth(isSelected ? 4 : 2);
+ holder.card.setCardBackgroundColor(isSelected ? holder.itemView.getContext().getColor(R.color.colorChip) : Color.WHITE);
+ holder.txtTime.setTextColor(isSelected ? holder.itemView.getContext().getColor(R.color.colorPrimary) : holder.itemView.getContext().getColor(R.color.colorTextPrimary));
+
+ holder.itemView.setOnClickListener(v -> {
+ int previousSelected = selectedPosition;
+ int currentPos = holder.getAdapterPosition();
+
+ if (currentPos != RecyclerView.NO_POSITION) {
+ selectedPosition = currentPos;
+ if (previousSelected != -1) {
+ notifyItemChanged(previousSelected);
+ }
+ notifyItemChanged(selectedPosition);
+ listener.onTimeSlotClick(slot);
+ }
+ });
+ }
+
+ @Override
+ public int getItemCount() {
+ return timeSlots.size();
+ }
+
+ static class ViewHolder extends RecyclerView.ViewHolder {
+ MaterialCardView card;
+ TextView txtTime;
+
+ ViewHolder(View itemView) {
+ super(itemView);
+ card = itemView.findViewById(R.id.cardTimeSlot);
+ txtTime = itemView.findViewById(R.id.txtTimeSlot);
+ }
+ }
+}
diff --git a/app/src/main/java/com/example/pap_teste/components/InteractiveRatingBar.java b/app/src/main/java/com/example/pap_teste/components/InteractiveRatingBar.java
index 6b0bc44..e16097a 100644
--- a/app/src/main/java/com/example/pap_teste/components/InteractiveRatingBar.java
+++ b/app/src/main/java/com/example/pap_teste/components/InteractiveRatingBar.java
@@ -51,6 +51,9 @@ public class InteractiveRatingBar extends LinearLayout {
int sizePx = (int) (starSizeDp * context.getResources().getDisplayMetrics().density);
int paddingPx = (int) (starPaddingDp * context.getResources().getDisplayMetrics().density);
+ stars.clear();
+ removeAllViews();
+
for (int i = 0; i < numStars; i++) {
ImageView star = new ImageView(context);
LayoutParams params = new LayoutParams(sizePx, sizePx);
@@ -91,11 +94,12 @@ public class InteractiveRatingBar extends LinearLayout {
}
private void calculateRatingFromTouch(float x) {
- if (stars.isEmpty()) return;
+ int count = stars.size();
+ if (count == 0) return;
double newRating = 0;
- for (int i = 0; i < numStars; i++) {
+ for (int i = 0; i < count; i++) {
ImageView star = stars.get(i);
float starLeft = star.getLeft();
float starRight = star.getRight();
@@ -116,7 +120,7 @@ public class InteractiveRatingBar extends LinearLayout {
}
// Clamp values
- newRating = Math.max(0.5, Math.min(newRating, numStars));
+ newRating = Math.max(0.5, Math.min(newRating, (double) count));
if (newRating != currentRating) {
currentRating = newRating;
@@ -128,7 +132,8 @@ public class InteractiveRatingBar extends LinearLayout {
}
private void updateStars(double rating, boolean animate) {
- for (int i = 0; i < numStars; i++) {
+ int count = stars.size();
+ for (int i = 0; i < count; i++) {
ImageView star = stars.get(i);
int previousResId = (Integer) (star.getTag() != null ? star.getTag() : 0);
int newResId;
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 be20023..6f5ab33 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
@@ -8,14 +8,13 @@ public class Reserva {
private String data;
private String hora;
private int pessoas;
- private String estado; // Pendente, Confirmada, Concluída, Cancelada, Recusada
+ private String estado;
public Reserva() {
- // Required for Firebase
}
- public Reserva(String id, String clienteEmail, String restauranteName, String restauranteEmail, String data,
- String hora, int pessoas, String estado) {
+ 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;
@@ -26,67 +25,27 @@ public class Reserva {
this.estado = estado;
}
- public String getId() {
- return id;
- }
+ public String getId() { return id; }
+ public void setId(String id) { this.id = id; }
- public void setId(String id) {
- this.id = id;
- }
+ public String getClienteEmail() { return clienteEmail; }
+ public void setClienteEmail(String clienteEmail) { this.clienteEmail = clienteEmail; }
- public String getClienteEmail() {
- return clienteEmail;
- }
+ public String getRestauranteName() { return restauranteName; }
+ public void setRestauranteName(String restauranteName) { this.restauranteName = restauranteName; }
- public void setClienteEmail(String clienteEmail) {
- this.clienteEmail = clienteEmail;
- }
+ public String getRestauranteEmail() { return restauranteEmail; }
+ public void setRestauranteEmail(String restauranteEmail) { this.restauranteEmail = restauranteEmail; }
- public String getRestauranteName() {
- return restauranteName;
- }
+ public String getData() { return data; }
+ public void setData(String data) { this.data = data; }
- public void setRestauranteName(String restauranteName) {
- this.restauranteName = restauranteName;
- }
+ public String getHora() { return hora; }
+ public void setHora(String hora) { this.hora = hora; }
- public String getRestauranteEmail() {
- return restauranteEmail;
- }
+ public int getPessoas() { return pessoas; }
+ public void setPessoas(int pessoas) { this.pessoas = pessoas; }
- 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;
- }
+ 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
index 19957c9..1993641 100644
--- a/app/src/main/java/com/example/pap_teste/models/Restaurant.java
+++ b/app/src/main/java/com/example/pap_teste/models/Restaurant.java
@@ -1,47 +1,75 @@
package com.example.pap_teste.models;
+import java.util.List;
+import java.util.Map;
+
public class Restaurant {
+ private String id;
private String name;
+ private String cuisine;
private String category;
private String email;
- private boolean available;
+ private String description;
+ private String imageURL;
private String logoUrl;
+ private double rating;
private Double ratingAvg;
- private Integer ratingCount;
+ private String address;
+ private Map openingHours; // { "open": "09:00", "close": "22:00" }
+ private List availableSlots;
+ private boolean favorite;
- // No-argument constructor required for Firebase
- public Restaurant() {
- }
+ public Restaurant() {}
- public Restaurant(String name, String category, String email, boolean available) {
+ public Restaurant(String name, String category, String email, boolean favorite, String logoUrl) {
this.name = name;
this.category = category;
this.email = email;
- this.available = available;
- }
-
- public Restaurant(String name, String category, String email, boolean available, String logoUrl) {
- this.name = name;
- this.category = category;
- this.email = email;
- this.available = available;
+ this.favorite = favorite;
this.logoUrl = logoUrl;
+ this.cuisine = category;
+ this.imageURL = logoUrl;
}
+ public String getId() { return id; }
+ public void setId(String id) { this.id = id; }
+
public String getName() { return name; }
- public String getCategory() { return category; }
- public String getEmail() { return email; }
- public boolean isAvailable() { return available; }
- public String getLogoUrl() { return logoUrl; }
-
public void setName(String name) { this.name = name; }
+
+ public String getCuisine() { return cuisine; }
+ public void setCuisine(String cuisine) { this.cuisine = cuisine; }
+
+ public String getCategory() { return category != null ? category : cuisine; }
public void setCategory(String category) { this.category = category; }
+
+ public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
- public void setAvailable(boolean available) { this.available = available; }
+
+ public String getDescription() { return description; }
+ public void setDescription(String description) { this.description = description; }
+
+ public String getImageURL() { return imageURL != null ? imageURL : logoUrl; }
+ public void setImageURL(String imageURL) { this.imageURL = imageURL; }
+
+ public String getLogoUrl() { return logoUrl != null ? logoUrl : imageURL; }
public void setLogoUrl(String logoUrl) { this.logoUrl = logoUrl; }
+ public double getRating() { return rating; }
+ public void setRating(double rating) { this.rating = rating; }
+
public Double getRatingAvg() { return ratingAvg; }
public void setRatingAvg(Double ratingAvg) { this.ratingAvg = ratingAvg; }
- public Integer getRatingCount() { return ratingCount; }
- public void setRatingCount(Integer ratingCount) { this.ratingCount = ratingCount; }
+
+ public String getAddress() { return address; }
+ public void setAddress(String address) { this.address = address; }
+
+ public Map getOpeningHours() { return openingHours; }
+ public void setOpeningHours(Map openingHours) { this.openingHours = openingHours; }
+
+ public List getAvailableSlots() { return availableSlots; }
+ public void setAvailableSlots(List availableSlots) { this.availableSlots = availableSlots; }
+
+ public boolean isFavorite() { return favorite; }
+ public void setFavorite(boolean favorite) { this.favorite = favorite; }
}
diff --git a/app/src/main/java/com/example/pap_teste/models/User.java b/app/src/main/java/com/example/pap_teste/models/User.java
new file mode 100644
index 0000000..e375b9d
--- /dev/null
+++ b/app/src/main/java/com/example/pap_teste/models/User.java
@@ -0,0 +1,33 @@
+package com.example.pap_teste.models;
+
+import com.google.firebase.Timestamp;
+import java.util.Date;
+
+public class User {
+ private String id;
+ private String name;
+ private String email;
+ private String photoURL;
+ private Timestamp createdAt;
+
+ public User() {}
+
+ public User(String id, String name, String email, String photoURL) {
+ this.id = id;
+ this.name = name;
+ this.email = email;
+ this.photoURL = photoURL;
+ this.createdAt = new Timestamp(new Date());
+ }
+
+ public String getId() { return id; }
+ public void setId(String id) { this.id = id; }
+ public String getName() { return name; }
+ public void setName(String name) { this.name = name; }
+ public String getEmail() { return email; }
+ public void setEmail(String email) { this.email = email; }
+ public String getPhotoURL() { return photoURL; }
+ public void setPhotoURL(String photoURL) { this.photoURL = photoURL; }
+ public Timestamp getCreatedAt() { return createdAt; }
+ public void setCreatedAt(Timestamp createdAt) { this.createdAt = createdAt; }
+}
diff --git a/app/src/main/res/drawable/gradient_overlay.xml b/app/src/main/res/drawable/gradient_overlay.xml
new file mode 100644
index 0000000..157399c
--- /dev/null
+++ b/app/src/main/res/drawable/gradient_overlay.xml
@@ -0,0 +1,7 @@
+
+
+
+
diff --git a/app/src/main/res/layout/activity_add_staff.xml b/app/src/main/res/layout/activity_add_staff.xml
deleted file mode 100644
index be2fff6..0000000
--- a/app/src/main/res/layout/activity_add_staff.xml
+++ /dev/null
@@ -1,164 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_client_dashboard_v2.xml b/app/src/main/res/layout/activity_client_dashboard_v2.xml
new file mode 100644
index 0000000..cda4791
--- /dev/null
+++ b/app/src/main/res/layout/activity_client_dashboard_v2.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_definicoes_admin.xml b/app/src/main/res/layout/activity_definicoes_admin.xml
deleted file mode 100644
index 74ea0c8..0000000
--- a/app/src/main/res/layout/activity_definicoes_admin.xml
+++ /dev/null
@@ -1,176 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/activity_detalhes_reservas.xml b/app/src/main/res/layout/activity_detalhes_reservas.xml
deleted file mode 100644
index 485e326..0000000
--- a/app/src/main/res/layout/activity_detalhes_reservas.xml
+++ /dev/null
@@ -1,183 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/activity_establishment_dashboard.xml b/app/src/main/res/layout/activity_establishment_dashboard.xml
deleted file mode 100644
index da28543..0000000
--- a/app/src/main/res/layout/activity_establishment_dashboard.xml
+++ /dev/null
@@ -1,477 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/activity_gerir_mesas.xml b/app/src/main/res/layout/activity_gerir_mesas.xml
deleted file mode 100644
index 3d8f7d9..0000000
--- a/app/src/main/res/layout/activity_gerir_mesas.xml
+++ /dev/null
@@ -1,172 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/activity_gestao_staff.xml b/app/src/main/res/layout/activity_gestao_staff.xml
deleted file mode 100644
index 89032ac..0000000
--- a/app/src/main/res/layout/activity_gestao_staff.xml
+++ /dev/null
@@ -1,188 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/activity_lista_espera.xml b/app/src/main/res/layout/activity_lista_espera.xml
deleted file mode 100644
index 7198404..0000000
--- a/app/src/main/res/layout/activity_lista_espera.xml
+++ /dev/null
@@ -1,159 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index e77998a..0ad3192 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -2,258 +2,163 @@
-
+ android:scaleType="centerCrop"
+ android:alpha="0.3"
+ android:src="@drawable/na_mesa" />
-
+
+
+
+
+
+
+
+
+
+
+
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:padding="24dp">
-
-
-
-
-
-
-
+ android:layout_marginBottom="24dp"
+ app:singleSelection="true"
+ app:checkedButton="@+id/btnEntrar">
-
+
+
+
+
+
+
+
+
+ android:inputType="textPersonName" />
+
-
+
-
+
+
-
-
+
-
+
+
-
+
-
-
+
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_onboarding.xml b/app/src/main/res/layout/activity_onboarding.xml
new file mode 100644
index 0000000..d45b566
--- /dev/null
+++ b/app/src/main/res/layout/activity_onboarding.xml
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_reservation.xml b/app/src/main/res/layout/activity_reservation.xml
new file mode 100644
index 0000000..44b04e5
--- /dev/null
+++ b/app/src/main/res/layout/activity_reservation.xml
@@ -0,0 +1,203 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_restaurant_detail.xml b/app/src/main/res/layout/activity_restaurant_detail.xml
new file mode 100644
index 0000000..fb679c5
--- /dev/null
+++ b/app/src/main/res/layout/activity_restaurant_detail.xml
@@ -0,0 +1,163 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml
new file mode 100644
index 0000000..c17b26b
--- /dev/null
+++ b/app/src/main/res/layout/fragment_home.xml
@@ -0,0 +1,174 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/fragment_my_reservations.xml b/app/src/main/res/layout/fragment_my_reservations.xml
new file mode 100644
index 0000000..76a4b80
--- /dev/null
+++ b/app/src/main/res/layout/fragment_my_reservations.xml
@@ -0,0 +1,71 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/fragment_profile.xml b/app/src/main/res/layout/fragment_profile.xml
new file mode 100644
index 0000000..0569ec9
--- /dev/null
+++ b/app/src/main/res/layout/fragment_profile.xml
@@ -0,0 +1,139 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/item_reserva_cliente.xml b/app/src/main/res/layout/item_reserva_cliente.xml
index 71c0035..1f22b2a 100644
--- a/app/src/main/res/layout/item_reserva_cliente.xml
+++ b/app/src/main/res/layout/item_reserva_cliente.xml
@@ -1,13 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/item_restaurant_featured.xml b/app/src/main/res/layout/item_restaurant_featured.xml
index f46e7ed..1c53842 100644
--- a/app/src/main/res/layout/item_restaurant_featured.xml
+++ b/app/src/main/res/layout/item_restaurant_featured.xml
@@ -1,11 +1,11 @@
@@ -14,112 +14,40 @@
android:layout_height="match_parent">
+ android:src="@drawable/na_mesa" />
-
-
-
-
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@drawable/gradient_overlay" />
+ android:orientation="vertical"
+ android:padding="16dp"
+ app:layout_constraintBottom_toBottomOf="parent">
-
-
-
+ android:textSize="18sp" />
+
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/item_time_slot.xml b/app/src/main/res/layout/item_time_slot.xml
new file mode 100644
index 0000000..27df94c
--- /dev/null
+++ b/app/src/main/res/layout/item_time_slot.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index fb0d14f..2857dc5 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -1,31 +1,33 @@
-
- #FF5A5F
- #FF3B30
- #FF5A5F
+
+ #1A237E
+ #000051
+ #3F51B5
- #FF000000
- #FFFFFFFF
- #F7F7F9
+ #121212
+ #FFFFFF
+ #FFFFFF
#FFFFFF
- #1A1A1A
- #757575
- #BDBDBD
+ #121212
+ #666666
+ #A0A0A0
+ #EEEEEE
- #34C759
- #FF3B30
- #FFCC00
- #E0E0E0
- #FFE0B2
+ #00897B
+ #D32F2F
+ #FFA000
+ #F5F5F5
+ #F8F9FA
+ #1A237E
+
+
+ #FFF3E0
#E65100
- #C8E6C9
- #1B5E20
- #FFCDD2
- #B71C1C
-
-
- #BE1F13
+ #E8F5E9
+ #2E7D32
+ #FFEBEE
+ #C62828
\ No newline at end of file
diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml
index d260148..1d32048 100644
--- a/app/src/main/res/values/themes.xml
+++ b/app/src/main/res/values/themes.xml
@@ -1,20 +1,45 @@
-
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test.txt b/test.txt
new file mode 100644
index 0000000..e69de29