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" /> + - + -