diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index d92e637..7cab3cb 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -3,6 +3,9 @@
xmlns:tools="http://schemas.android.com/tools">
+
+
+
-
+
-
+
+
+
diff --git a/app/src/main/java/com/example/pap_teste/BloqueioHorarioActivity.java b/app/src/main/java/com/example/pap_teste/BloqueioHorarioActivity.java
deleted file mode 100644
index 627a269..0000000
--- a/app/src/main/java/com/example/pap_teste/BloqueioHorarioActivity.java
+++ /dev/null
@@ -1,36 +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;
-
-public class BloqueioHorarioActivity extends AppCompatActivity {
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- EdgeToEdge.enable(this);
- setContentView(R.layout.activity_bloqueio_horario);
- ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.bloqueioRoot), (v, insets) -> {
- Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
- v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
- return insets;
- });
-
- Button back = findViewById(R.id.btnVoltar);
- if (back != null) {
- back.setOnClickListener(v -> finish());
- }
- }
-}
-
-
-
-
-
diff --git a/app/src/main/java/com/example/pap_teste/CheckInAntecipadoActivity.java b/app/src/main/java/com/example/pap_teste/CheckInAntecipadoActivity.java
index c2e0753..25f826c 100644
--- a/app/src/main/java/com/example/pap_teste/CheckInAntecipadoActivity.java
+++ b/app/src/main/java/com/example/pap_teste/CheckInAntecipadoActivity.java
@@ -1,16 +1,40 @@
package com.example.pap_teste;
+import android.Manifest;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.location.Location;
+import android.location.LocationListener;
+import android.location.LocationManager;
import android.os.Bundle;
+import android.widget.Button;
+import android.widget.TextView;
+import android.widget.Toast;
import androidx.activity.EdgeToEdge;
+import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
+import androidx.core.app.ActivityCompat;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
-import android.widget.Button;
+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;
-public class CheckInAntecipadoActivity extends AppCompatActivity {
+public class CheckInAntecipadoActivity extends AppCompatActivity implements LocationListener {
+
+ private TextView txtDistancia, txtStatus;
+ private Button btnConfirmarChegada;
+ private LocationManager locationManager;
+ private DatabaseReference databaseReference;
+
+ private double restaurantLat, restaurantLon;
+ private int securityDistance = 500; // default 500m
+ private boolean settingsLoaded = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -23,14 +47,114 @@ public class CheckInAntecipadoActivity extends AppCompatActivity {
return insets;
});
+ txtDistancia = findViewById(R.id.txtDistancia);
+ txtStatus = findViewById(R.id.txtStatusDistancia);
+ btnConfirmarChegada = findViewById(R.id.btnConfirmarChegada);
Button back = findViewById(R.id.btnVoltar);
+
if (back != null) {
back.setOnClickListener(v -> finish());
}
+
+ String restaurantEmail = getIntent().getStringExtra("restaurant_email");
+ if (restaurantEmail != null) {
+ String restaurantId = restaurantEmail.replace(".", "_").replace("@", "_at_");
+ loadRestaurantSettings(restaurantId);
+ } else {
+ txtStatus.setText("Erro: Restaurante não identificado.");
+ }
+
+ locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
+ startLocationUpdates();
+
+ btnConfirmarChegada.setOnClickListener(v -> {
+ Toast.makeText(this, "Chegada confirmada com sucesso!", Toast.LENGTH_LONG).show();
+ finish();
+ });
+ }
+
+ private void loadRestaurantSettings(String restaurantId) {
+ databaseReference = FirebaseDatabase.getInstance().getReference().child("users").child(restaurantId);
+ databaseReference.addListenerForSingleValueEvent(new ValueEventListener() {
+ @Override
+ public void onDataChange(@NonNull DataSnapshot snapshot) {
+ if (snapshot.exists()) {
+ Double lat = snapshot.child("latitude").getValue(Double.class);
+ Double lon = snapshot.child("longitude").getValue(Double.class);
+ Integer dist = snapshot.child("securityDistance").getValue(Integer.class);
+
+ restaurantLat = lat != null ? lat : 0.0;
+ restaurantLon = lon != null ? lon : 0.0;
+ securityDistance = dist != null ? dist : 500;
+ settingsLoaded = true;
+ } else {
+ txtStatus.setText("Aviso: Definições do restaurante não encontradas. Usando valores padrão.");
+ settingsLoaded = true; // Use defaults
+ }
+ }
+
+ @Override
+ public void onCancelled(@NonNull DatabaseError error) {
+ txtStatus.setText("Erro ao carregar definições do restaurante.");
+ }
+ });
+ }
+
+ private void startLocationUpdates() {
+ if (ActivityCompat.checkSelfPermission(this,
+ Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
+ ActivityCompat.checkSelfPermission(this,
+ Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
+ txtStatus.setText("Permissão de localização negada.");
+ return;
+ }
+ try {
+ locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 5000, 5, this);
+ locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 5000, 5, this);
+ } catch (Exception e) {
+ txtStatus.setText("Erro ao iniciar localização: " + e.getMessage());
+ }
+ }
+
+ @Override
+ public void onLocationChanged(@NonNull Location location) {
+ if (!settingsLoaded)
+ return;
+
+ float[] results = new float[1];
+ Location.distanceBetween(location.getLatitude(), location.getLongitude(), restaurantLat, restaurantLon,
+ results);
+ float distanceInMeters = results[0];
+
+ txtDistancia.setText(String.format("Distância: %.0f metros", distanceInMeters));
+
+ if (distanceInMeters <= securityDistance) {
+ txtStatus.setText("Está no raio de segurança. Pode confirmar a sua chegada.");
+ txtStatus.setTextColor(getResources().getColor(android.R.color.holo_green_dark));
+ btnConfirmarChegada.setEnabled(true);
+ } else {
+ txtStatus.setText(String.format("Está fora do raio de segurança (%dm). Aproxime-se para fazer check-in.",
+ securityDistance));
+ txtStatus.setTextColor(getResources().getColor(android.R.color.holo_red_dark));
+ btnConfirmarChegada.setEnabled(false);
+ }
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ locationManager.removeUpdates(this);
+ }
+
+ @Override
+ public void onStatusChanged(String provider, int status, Bundle extras) {
+ }
+
+ @Override
+ public void onProviderEnabled(@NonNull String provider) {
+ }
+
+ @Override
+ public void onProviderDisabled(@NonNull String provider) {
}
}
-
-
-
-
-
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 a2ce9d1..05a7c11 100644
--- a/app/src/main/java/com/example/pap_teste/ClientDashboardActivity.java
+++ b/app/src/main/java/com/example/pap_teste/ClientDashboardActivity.java
@@ -11,70 +11,89 @@ import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
+import androidx.recyclerview.widget.RecyclerView;
+import com.example.pap_teste.models.FoodCategory;
+import java.util.ArrayList;
+import java.util.List;
+
public class ClientDashboardActivity extends AppCompatActivity {
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- EdgeToEdge.enable(this);
- setContentView(R.layout.activity_client_dashboard);
- 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;
- });
+ private String email, displayName, role;
+ private TextView txtGreeting;
+ private androidx.activity.result.ActivityResultLauncher profileLauncher;
- TextView txtGreeting = findViewById(R.id.txtClientGreeting);
- TextView txtStatus = findViewById(R.id.txtClientStatus);
- TextView txtRole = findViewById(R.id.txtClientRole);
- TextView txtReservationStatus = findViewById(R.id.txtReservationStatus);
- TextView txtReservationSubtitle = findViewById(R.id.txtReservationSubtitle);
- Button btnBack = findViewById(R.id.btnVoltar);
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ EdgeToEdge.enable(this);
+ setContentView(R.layout.activity_client_dashboard);
+ 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;
+ });
- String actionMode = getIntent().getStringExtra(MainActivity.EXTRA_ACTION_MODE);
- String displayName = getIntent().getStringExtra(MainActivity.EXTRA_DISPLAY_NAME);
- String role = getIntent().getStringExtra(MainActivity.EXTRA_ROLE);
+ txtGreeting = findViewById(R.id.txtClientGreeting);
- boolean isNewAccount = "CRIAR".equalsIgnoreCase(actionMode);
- txtGreeting.setText(String.format("Olá, %s", displayName != null ? displayName : "convidado"));
- txtRole.setText(String.format("Função: %s", role != null ? role : "CLIENTE"));
- txtStatus.setText(isNewAccount
- ? "Conta criada com sucesso! Configure as suas preferências para começarmos."
- : "Bom tê-lo de volta! Já deixámos tudo pronto para a sua próxima reserva.");
+ email = getIntent().getStringExtra(MainActivity.EXTRA_EMAIL);
+ displayName = getIntent().getStringExtra(MainActivity.EXTRA_DISPLAY_NAME);
+ role = getIntent().getStringExtra(MainActivity.EXTRA_ROLE);
- txtReservationStatus.setText("Próxima reserva");
- txtReservationSubtitle.setText("Mesa para 2 • Amanhã às 20h • Sabor & Arte");
+ profileLauncher = registerForActivityResult(
+ new androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult(),
+ result -> {
+ if (result.getResultCode() == RESULT_OK) {
+ android.widget.Toast.makeText(this,
+ "Perfil atualizado. Reinicie para ver mudanças.",
+ android.widget.Toast.LENGTH_SHORT).show();
+ }
+ });
- Button btnNewReservation = findViewById(R.id.btnNovaReserva);
- Button btnExplore = findViewById(R.id.btnExplorar);
- Button btnFavorites = findViewById(R.id.btnFavoritos);
-
- Button btnCheckIn = findViewById(R.id.btnCheckIn);
- Button btnShare = findViewById(R.id.btnPartilhar);
-
- btnNewReservation.setOnClickListener(v ->
- startActivity(new Intent(this, NovaReservaActivity.class))
- );
-
- btnExplore.setOnClickListener(v ->
- startActivity(new Intent(this, ExplorarRestaurantesActivity.class))
- );
-
- btnFavorites.setOnClickListener(v ->
- startActivity(new Intent(this, FavoritosActivity.class))
- );
-
- btnCheckIn.setOnClickListener(v ->
- startActivity(new Intent(this, CheckInAntecipadoActivity.class))
- );
-
- btnShare.setOnClickListener(v ->
- startActivity(new Intent(this, PartilharReservaActivity.class))
- );
-
- if (btnBack != null) {
- btnBack.setOnClickListener(v -> finish());
+ updateGreeting();
+ setupCategories();
+ setupActions();
}
- }
-}
+ private void updateGreeting() {
+ txtGreeting.setText(String.format("Olá, %s", displayName != null ? displayName : "convidado"));
+ }
+
+ private void setupCategories() {
+ RecyclerView rv = findViewById(R.id.rvCategories);
+ List cats = new ArrayList<>();
+ cats.add(new FoodCategory("Carnes", R.drawable.cat_carnes));
+ cats.add(new FoodCategory("Massas", R.drawable.cat_massas));
+ cats.add(new FoodCategory("Sushi", R.drawable.cat_sushi));
+ cats.add(new FoodCategory("Pizzas", R.drawable.ic_launcher_background));
+ cats.add(new FoodCategory("Sobremesas", R.drawable.ic_launcher_background));
+
+ FoodCategoryAdapter adapter = new FoodCategoryAdapter(cats);
+ rv.setAdapter(adapter);
+ }
+
+ private void setupActions() {
+ 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);
+ profileLauncher.launch(intent);
+ });
+
+ findViewById(R.id.btnVoltar).setOnClickListener(v -> finish());
+
+ findViewById(R.id.btnCheckIn).setOnClickListener(v -> {
+ Intent intent = new Intent(this, CheckInAntecipadoActivity.class);
+ intent.putExtra("restaurant_email", "sabor_arte@restaurante.com");
+ startActivity(intent);
+ });
+
+ findViewById(R.id.btnPartilhar).setOnClickListener(
+ v -> startActivity(new Intent(this, PartilharReservaActivity.class)));
+
+ findViewById(R.id.btnNovaReserva)
+ .setOnClickListener(v -> startActivity(new Intent(this, NovaReservaActivity.class)));
+
+ findViewById(R.id.btnExplorar).setOnClickListener(
+ v -> startActivity(new Intent(this, ExplorarRestaurantesActivity.class)));
+ }
+}
diff --git a/app/src/main/java/com/example/pap_teste/DefinicoesAdminActivity.java b/app/src/main/java/com/example/pap_teste/DefinicoesAdminActivity.java
new file mode 100644
index 0000000..7acce4e
--- /dev/null
+++ b/app/src/main/java/com/example/pap_teste/DefinicoesAdminActivity.java
@@ -0,0 +1,129 @@
+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;
+
+public class DefinicoesAdminActivity extends AppCompatActivity {
+
+ private EditText inputRadius, inputLatitude, inputLongitude;
+ private DatabaseReference databaseReference;
+ private String documentId;
+
+ @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("users");
+
+ inputRadius = findViewById(R.id.inputRadius);
+ inputLatitude = findViewById(R.id.inputLatitude);
+ inputLongitude = findViewById(R.id.inputLongitude);
+ Button btnSave = findViewById(R.id.btnSaveSettings);
+ Button btnBack = findViewById(R.id.btnVoltar);
+
+ if (btnBack != null) {
+ btnBack.setOnClickListener(v -> finish());
+ }
+
+ loadCurrentSettings();
+
+ btnSave.setOnClickListener(v -> saveSettings());
+ }
+
+ 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("latitude")) {
+ Object val = snapshot.child("latitude").getValue();
+ inputLatitude.setText(val != null ? val.toString() : "");
+ }
+ if (snapshot.hasChild("longitude")) {
+ Object val = snapshot.child("longitude").getValue();
+ inputLongitude.setText(val != null ? val.toString() : "");
+ }
+ }
+ }
+
+ @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 latStr = inputLatitude.getText().toString().trim();
+ String lonStr = inputLongitude.getText().toString().trim();
+
+ if (TextUtils.isEmpty(radiusStr) || TextUtils.isEmpty(latStr) || TextUtils.isEmpty(lonStr)) {
+ Toast.makeText(this, "Preencha todos os campos.", Toast.LENGTH_SHORT).show();
+ return;
+ }
+
+ try {
+ int radius = Integer.parseInt(radiusStr);
+ double lat = Double.parseDouble(latStr);
+ double lon = Double.parseDouble(lonStr);
+
+ Map updates = new HashMap<>();
+ updates.put("securityDistance", radius);
+ updates.put("latitude", lat);
+ updates.put("longitude", lon);
+
+ 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, "Valores inválidos.", 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
index dbb6dcd..2fa0d74 100644
--- a/app/src/main/java/com/example/pap_teste/DetalhesReservasActivity.java
+++ b/app/src/main/java/com/example/pap_teste/DetalhesReservasActivity.java
@@ -25,6 +25,7 @@ public class DetalhesReservasActivity extends AppCompatActivity {
private TextView txtNotas;
private TextView txtEstado;
private TextView txtMensagem;
+ private Button btnConfirmar, btnRecusar, btnApagar;
private int selectedIndex = -1;
@Override
@@ -51,6 +52,10 @@ public class DetalhesReservasActivity extends AppCompatActivity {
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());
@@ -61,6 +66,7 @@ public class DetalhesReservasActivity extends AppCompatActivity {
reservas.add(new ReservaItem("Ana Ribeiro", "Mesa 12", "20h00", 4, "Aniversário", "Confirmada"));
reservas.add(new ReservaItem("Bruno Costa", "Mesa 03", "21h15", 2, "Preferência por janela", "Pendente"));
reservas.add(new ReservaItem("Carla Silva", "Mesa 07", "19h30", 3, "Levar bolo para a mesa", "Pendente"));
+ reservas.add(new ReservaItem("Duarte Neves", "Mesa 01", "22h00", 2, "", "Concluída"));
}
private void setupList() {
@@ -75,16 +81,59 @@ public class DetalhesReservasActivity extends AppCompatActivity {
}
private void setupActions() {
- Button btnConfirmar = findViewById(R.id.btnConfirmarReserva);
- Button btnCancelar = findViewById(R.id.btnCancelarReserva);
-
if (btnConfirmar != null) {
- btnConfirmar.setOnClickListener(v -> atualizarEstadoSelecionado("Confirmada"));
+ btnConfirmar.setOnClickListener(v -> {
+ ReservaItem item = reservas.get(selectedIndex);
+ if ("Pendente".equals(item.estado)) {
+ atualizarEstadoSelecionado("Confirmada");
+ } else if ("Confirmada".equals(item.estado)) {
+ atualizarEstadoSelecionado("Concluída");
+ }
+ });
}
- if (btnCancelar != null) {
- btnCancelar.setOnClickListener(v -> atualizarEstadoSelecionado("Cancelada"));
+ if (btnRecusar != null) {
+ btnRecusar.setOnClickListener(v -> showRecusarDialog());
}
+
+ if (btnApagar != null) {
+ btnApagar.setOnClickListener(v -> apagarReserva());
+ }
+ }
+
+ 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 Reserva")
+ .setMessage("Tem a certeza que deseja apagar esta reserva?")
+ .setPositiveButton("Apagar", (dialog, which) -> {
+ reservas.remove(selectedIndex);
+ selectedIndex = -1;
+ txtInfo.setText("Selecione uma reserva");
+ txtNotas.setText("");
+ txtEstado.setText("Estado:");
+ txtMensagem.setText("Reserva apagada com sucesso.");
+ toggleButtons(null);
+ refreshList();
+ })
+ .setNegativeButton("Voltar", null)
+ .show();
}
private void atualizarEstadoSelecionado(String novoEstado) {
@@ -104,6 +153,41 @@ public class DetalhesReservasActivity extends AppCompatActivity {
txtInfo.setText(String.format("%s • %s • %s • %dp", item.nomeCliente, item.mesa, item.hora, item.pessoas));
txtNotas.setText(item.notas);
txtEstado.setText(String.format("Estado: %s", item.estado));
+ toggleButtons(item);
+ }
+
+ private void toggleButtons(ReservaItem item) {
+ if (item == null) {
+ btnConfirmar.setVisibility(android.view.View.GONE);
+ btnRecusar.setVisibility(android.view.View.GONE);
+ btnApagar.setVisibility(android.view.View.GONE);
+ return;
+ }
+
+ switch (item.estado) {
+ case "Pendente":
+ btnConfirmar.setText("Confirmar");
+ btnConfirmar.setVisibility(android.view.View.VISIBLE);
+ btnRecusar.setVisibility(android.view.View.VISIBLE);
+ btnApagar.setVisibility(android.view.View.GONE);
+ break;
+ case "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);
+ break;
+ case "Concluída":
+ btnConfirmar.setVisibility(android.view.View.GONE);
+ btnRecusar.setVisibility(android.view.View.GONE);
+ btnApagar.setVisibility(android.view.View.VISIBLE);
+ break;
+ default: // Recusada or Cancelada
+ btnConfirmar.setVisibility(android.view.View.GONE);
+ btnRecusar.setVisibility(android.view.View.GONE);
+ btnApagar.setVisibility(android.view.View.VISIBLE); // Allow deleting refused ones as well
+ break;
+ }
}
private void refreshList() {
@@ -133,13 +217,3 @@ public class DetalhesReservasActivity extends AppCompatActivity {
}
}
}
-
-
-
-
-
-
-
-
-
-
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 9043058..af69294 100644
--- a/app/src/main/java/com/example/pap_teste/EstablishmentDashboardActivity.java
+++ b/app/src/main/java/com/example/pap_teste/EstablishmentDashboardActivity.java
@@ -13,67 +13,56 @@ 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;
- });
+ @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);
+ 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);
+ 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.");
+ 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.");
- Button btnOpenWalkIns = findViewById(R.id.btnAbrirEspera);
- Button btnBlockTime = findViewById(R.id.btnCriarBloqueio);
- Button btnStaff = findViewById(R.id.btnGestaoStaff);
- Button btnReports = findViewById(R.id.btnVerRelatorios);
- Button btnGerirMesas = findViewById(R.id.btnGerirMesas);
- Button btnDetalhesReservas = findViewById(R.id.btnDetalhesReservas);
- Button btnBack = findViewById(R.id.btnVoltar);
+ Button btnOpenWalkIns = findViewById(R.id.btnAbrirEspera);
+ Button btnStaff = findViewById(R.id.btnGestaoStaff);
+ Button btnGerirMesas = findViewById(R.id.btnGerirMesas);
+ Button btnDetails = findViewById(R.id.btnDetalhesReservas);
+ Button btnSettings = findViewById(R.id.btnDefinicoes);
+ Button btnBack = findViewById(R.id.btnVoltar);
- btnOpenWalkIns.setOnClickListener(v ->
- startActivity(new Intent(this, ListaEsperaActivity.class))
- );
+ btnOpenWalkIns.setOnClickListener(v -> startActivity(new Intent(this, ListaEsperaActivity.class)));
- btnBlockTime.setOnClickListener(v ->
- startActivity(new Intent(this, BloqueioHorarioActivity.class))
- );
+ btnStaff.setOnClickListener(v -> startActivity(new Intent(this, GestaoStaffActivity.class)));
- btnStaff.setOnClickListener(v ->
- startActivity(new Intent(this, GestaoStaffActivity.class))
- );
+ btnGerirMesas.setOnClickListener(v -> startActivity(new Intent(this, GerirMesasActivity.class)));
- btnReports.setOnClickListener(v ->
- startActivity(new Intent(this, RelatoriosActivity.class))
- );
+ btnDetails.setOnClickListener(v -> startActivity(new Intent(this, DetalhesReservasActivity.class)));
- btnGerirMesas.setOnClickListener(v ->
- startActivity(new Intent(this, GerirMesasActivity.class))
- );
+ btnSettings.setOnClickListener(v -> {
+ Intent intent = new Intent(this, DefinicoesAdminActivity.class);
+ intent.putExtra(MainActivity.EXTRA_EMAIL, getIntent().getStringExtra(MainActivity.EXTRA_EMAIL));
+ startActivity(intent);
+ });
- btnDetalhesReservas.setOnClickListener(v ->
- startActivity(new Intent(this, DetalhesReservasActivity.class))
- );
+ if (btnBack != null) {
- if (btnBack != null) {
- btnBack.setOnClickListener(v -> finish());
+ btnBack.setOnClickListener(v -> finish());
+ }
}
- }
}
-
diff --git a/app/src/main/java/com/example/pap_teste/FoodCategoryAdapter.java b/app/src/main/java/com/example/pap_teste/FoodCategoryAdapter.java
new file mode 100644
index 0000000..29acfc0
--- /dev/null
+++ b/app/src/main/java/com/example/pap_teste/FoodCategoryAdapter.java
@@ -0,0 +1,55 @@
+package com.example.pap_teste;
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.example.pap_teste.models.FoodCategory;
+
+import java.util.List;
+
+public class FoodCategoryAdapter extends RecyclerView.Adapter {
+
+ private final List categories;
+
+ public FoodCategoryAdapter(List categories) {
+ this.categories = categories;
+ }
+
+ @NonNull
+ @Override
+ public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_food_category, parent, false);
+ return new ViewHolder(view);
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
+ FoodCategory category = categories.get(position);
+ holder.txtName.setText(category.getName());
+ if (category.getImageResId() != 0) {
+ holder.imgCategory.setImageResource(category.getImageResId());
+ }
+ }
+
+ @Override
+ public int getItemCount() {
+ return categories.size();
+ }
+
+ public static class ViewHolder extends RecyclerView.ViewHolder {
+ ImageView imgCategory;
+ TextView txtName;
+
+ public ViewHolder(@NonNull View itemView) {
+ super(itemView);
+ imgCategory = itemView.findViewById(R.id.imgCategory);
+ txtName = itemView.findViewById(R.id.txtCategoryName);
+ }
+ }
+}
diff --git a/app/src/main/java/com/example/pap_teste/GerirMesasActivity.java b/app/src/main/java/com/example/pap_teste/GerirMesasActivity.java
index 78456ba..3dd8329 100644
--- a/app/src/main/java/com/example/pap_teste/GerirMesasActivity.java
+++ b/app/src/main/java/com/example/pap_teste/GerirMesasActivity.java
@@ -37,6 +37,7 @@ public class GerirMesasActivity extends AppCompatActivity {
private Spinner spinnerEstado;
private TextView txtMensagem;
private DatabaseReference mDatabase;
+ private Mesa selectedMesa = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -88,6 +89,8 @@ public class GerirMesasActivity extends AppCompatActivity {
for (DataSnapshot postSnapshot : snapshot.getChildren()) {
Mesa mesa = postSnapshot.getValue(Mesa.class);
if (mesa != null) {
+ // 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());
@@ -106,6 +109,7 @@ public class GerirMesasActivity extends AppCompatActivity {
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()));
@@ -128,6 +132,34 @@ public class GerirMesasActivity extends AppCompatActivity {
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() {
@@ -162,6 +194,10 @@ public class GerirMesasActivity extends AppCompatActivity {
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);
@@ -169,8 +205,7 @@ public class GerirMesasActivity extends AppCompatActivity {
}
// Clearing inputs
- inputNumero.setText("");
- inputCapacidade.setText("");
+ limparCampos();
}
private Mesa findMesa(int numero) {
diff --git a/app/src/main/java/com/example/pap_teste/GestaoStaffActivity.java b/app/src/main/java/com/example/pap_teste/GestaoStaffActivity.java
index d2075a5..f82deed 100644
--- a/app/src/main/java/com/example/pap_teste/GestaoStaffActivity.java
+++ b/app/src/main/java/com/example/pap_teste/GestaoStaffActivity.java
@@ -169,6 +169,14 @@ public class GestaoStaffActivity extends AppCompatActivity {
}
});
}
+
+ 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() {
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 003a968..fa462b5 100644
--- a/app/src/main/java/com/example/pap_teste/MainActivity.java
+++ b/app/src/main/java/com/example/pap_teste/MainActivity.java
@@ -15,6 +15,12 @@ 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 androidx.activity.result.ActivityResultLauncher;
+import androidx.activity.result.contract.ActivityResultContracts;
import com.google.firebase.FirebaseApp;
import com.google.firebase.auth.FirebaseAuth;
@@ -62,6 +68,22 @@ public class MainActivity extends AppCompatActivity {
private FirebaseAuth firebaseAuth;
private DatabaseReference databaseReference;
+ private final ActivityResultLauncher locationPermissionRequest = registerForActivityResult(
+ new ActivityResultContracts.RequestMultiplePermissions(), result -> {
+ Boolean fineLocationGranted = result.getOrDefault(
+ Manifest.permission.ACCESS_FINE_LOCATION, false);
+ Boolean coarseLocationGranted = result.getOrDefault(
+ Manifest.permission.ACCESS_COARSE_LOCATION, false);
+ if (fineLocationGranted != null && fineLocationGranted) {
+ // Precise location access granted.
+ } else if (coarseLocationGranted != null && coarseLocationGranted) {
+ // Only approximate location access granted.
+ } else {
+ Toast.makeText(this, "A permissão de localização é necessária para o check-in.", Toast.LENGTH_LONG)
+ .show();
+ }
+ });
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -81,6 +103,28 @@ public class MainActivity extends AppCompatActivity {
setupTypeToggle();
setupActionToggle();
setupPrimaryAction();
+ checkLocationPermissions();
+ }
+
+ private void checkLocationPermissions() {
+ if (ContextCompat.checkSelfPermission(this,
+ Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
+ new AlertDialog.Builder(this)
+ .setTitle("Partilha de localização")
+ .setMessage(
+ "Para permitir o check-in antecipado, precisamos de saber a sua distância ao restaurante. Deseja permitir a partilha de localização?")
+ .setPositiveButton("Sim", (dialog, which) -> {
+ locationPermissionRequest.launch(new String[] {
+ Manifest.permission.ACCESS_FINE_LOCATION,
+ Manifest.permission.ACCESS_COARSE_LOCATION
+ });
+ })
+ .setNegativeButton("Não", (dialog, which) -> {
+ Toast.makeText(this, "A localização foi recusada. O check-in poderá não funcionar.",
+ Toast.LENGTH_SHORT).show();
+ })
+ .show();
+ }
}
private void bindViews() {
@@ -341,7 +385,8 @@ public class MainActivity extends AppCompatActivity {
DataSnapshot snapshot = task.getResult();
if (snapshot == null || !snapshot.exists()) {
- Toast.makeText(this, "Conta sem perfil na cloud. A entrar em modo básico.", Toast.LENGTH_SHORT).show();
+ // Toast.makeText(this, "Conta sem perfil na cloud. A entrar em modo básico.",
+ // Toast.LENGTH_SHORT).show();
navigateToDashboard(email, fallbackName, resolvedRole);
return;
}
diff --git a/app/src/main/java/com/example/pap_teste/ProfileDashboardActivity.java b/app/src/main/java/com/example/pap_teste/ProfileDashboardActivity.java
new file mode 100644
index 0000000..55f3d28
--- /dev/null
+++ b/app/src/main/java/com/example/pap_teste/ProfileDashboardActivity.java
@@ -0,0 +1,94 @@
+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.appcompat.app.AppCompatActivity;
+import androidx.core.graphics.Insets;
+import androidx.core.view.ViewCompat;
+import androidx.core.view.WindowInsetsCompat;
+
+import com.google.firebase.database.DatabaseReference;
+import com.google.firebase.database.FirebaseDatabase;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class ProfileDashboardActivity extends AppCompatActivity {
+
+ private EditText inputName;
+ private String email, documentId;
+ private DatabaseReference databaseReference;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ EdgeToEdge.enable(this);
+ setContentView(R.layout.activity_profile_dashboard);
+ ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.profileRoot), (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);
+ String currentName = getIntent().getStringExtra(MainActivity.EXTRA_DISPLAY_NAME);
+
+ if (email != null) {
+ documentId = email.replace(".", "_").replace("@", "_at_");
+ }
+
+ databaseReference = FirebaseDatabase.getInstance().getReference().child("users");
+
+ inputName = findViewById(R.id.inputProfileName);
+ if (currentName != null) {
+ inputName.setText(currentName);
+ }
+
+ Button btnSave = findViewById(R.id.btnSaveProfile);
+ Button btnBack = findViewById(R.id.btnVoltar);
+ Button btnFavs = findViewById(R.id.btnFavoritos);
+ Button btnRes = findViewById(R.id.btnMinhasReservas);
+
+ btnBack.setOnClickListener(v -> finish());
+
+ btnSave.setOnClickListener(v -> saveProfile());
+
+ btnFavs.setOnClickListener(v -> {
+ Toast.makeText(this, "A abrir Favoritos...", Toast.LENGTH_SHORT).show();
+ // startActivity(new Intent(this, FavoritosActivity.class));
+ });
+
+ btnRes.setOnClickListener(v -> {
+ Toast.makeText(this, "A abrir Reservas...", Toast.LENGTH_SHORT).show();
+ // startActivity(new Intent(this, DetalhesReservasActivity.class));
+ });
+ }
+
+ private void saveProfile() {
+ if (documentId == null)
+ return;
+
+ String newName = inputName.getText().toString().trim();
+ if (TextUtils.isEmpty(newName)) {
+ Toast.makeText(this, "Indique um nome.", Toast.LENGTH_SHORT).show();
+ return;
+ }
+
+ Map updates = new HashMap<>();
+ updates.put("displayName", newName);
+
+ databaseReference.child(documentId).updateChildren(updates)
+ .addOnSuccessListener(aVoid -> {
+ Toast.makeText(this, "Perfil atualizado!", Toast.LENGTH_SHORT).show();
+ setResult(RESULT_OK);
+ finish();
+ })
+ .addOnFailureListener(
+ e -> Toast.makeText(this, "Falha ao atualizar perfil.", Toast.LENGTH_SHORT).show());
+ }
+}
diff --git a/app/src/main/java/com/example/pap_teste/RelatoriosActivity.java b/app/src/main/java/com/example/pap_teste/RelatoriosActivity.java
deleted file mode 100644
index dc401ab..0000000
--- a/app/src/main/java/com/example/pap_teste/RelatoriosActivity.java
+++ /dev/null
@@ -1,31 +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;
-
-public class RelatoriosActivity extends AppCompatActivity {
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- EdgeToEdge.enable(this);
- setContentView(R.layout.activity_relatorios);
- ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.relatoriosRoot), (v, insets) -> {
- Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
- v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
- return insets;
- });
-
- Button back = findViewById(R.id.btnVoltar);
- if (back != null) {
- back.setOnClickListener(v -> finish());
- }
- }
-}
diff --git a/app/src/main/java/com/example/pap_teste/models/FoodCategory.java b/app/src/main/java/com/example/pap_teste/models/FoodCategory.java
new file mode 100644
index 0000000..44e491a
--- /dev/null
+++ b/app/src/main/java/com/example/pap_teste/models/FoodCategory.java
@@ -0,0 +1,19 @@
+package com.example.pap_teste.models;
+
+public class FoodCategory {
+ private String name;
+ private int imageResId;
+
+ public FoodCategory(String name, int imageResId) {
+ this.name = name;
+ this.imageResId = imageResId;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public int getImageResId() {
+ return imageResId;
+ }
+}
diff --git a/app/src/main/res/drawable/cat_carnes.png b/app/src/main/res/drawable/cat_carnes.png
new file mode 100644
index 0000000..10f3ba0
Binary files /dev/null and b/app/src/main/res/drawable/cat_carnes.png differ
diff --git a/app/src/main/res/drawable/cat_massas.png b/app/src/main/res/drawable/cat_massas.png
new file mode 100644
index 0000000..c13db2d
Binary files /dev/null and b/app/src/main/res/drawable/cat_massas.png differ
diff --git a/app/src/main/res/drawable/cat_sushi.png b/app/src/main/res/drawable/cat_sushi.png
new file mode 100644
index 0000000..a61acda
Binary files /dev/null and b/app/src/main/res/drawable/cat_sushi.png differ
diff --git a/app/src/main/res/layout/activity_bloqueio_horario.xml b/app/src/main/res/layout/activity_bloqueio_horario.xml
deleted file mode 100644
index 090e2df..0000000
--- a/app/src/main/res/layout/activity_bloqueio_horario.xml
+++ /dev/null
@@ -1,53 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/activity_checkin_antecipado.xml b/app/src/main/res/layout/activity_checkin_antecipado.xml
index 67ae8cd..d7e5c7d 100644
--- a/app/src/main/res/layout/activity_checkin_antecipado.xml
+++ b/app/src/main/res/layout/activity_checkin_antecipado.xml
@@ -38,13 +38,55 @@
android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="12dp"
- android:text="Aqui o cliente poderá confirmar a chegada antes do horário marcado."
+ android:text="Aqui poderá confirmar a sua chegada ao restaurante."
android:textSize="14sp"
android:textColor="#4D4D4D"
app:layout_constraintTop_toBottomOf="@id/txtTituloCheckin"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_client_dashboard.xml b/app/src/main/res/layout/activity_client_dashboard.xml
index eb40e60..1ed9aac 100644
--- a/app/src/main/res/layout/activity_client_dashboard.xml
+++ b/app/src/main/res/layout/activity_client_dashboard.xml
@@ -5,273 +5,287 @@
android:id="@+id/clientRoot"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:background="#F7F7F7"
+ android:background="#FFFFFF"
tools:context=".ClientDashboardActivity">
+
+
+
+
+
+
+
+
+ android:background="@android:color/transparent"
+ android:textColor="#FF5252"
+ app:layout_constraintBottom_toBottomOf="@id/cardProfile"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintTop_toTopOf="@id/cardProfile" />
+ app:layout_constraintTop_toBottomOf="@id/cardProfile">
+ android:paddingBottom="24dp">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ android:layout_gravity="center"
+ android:layout_marginTop="8dp"
+ android:text="Modo Cliente"
+ android:textColor="#BDBDBD"
+ android:textSize="12sp" />
+
diff --git a/app/src/main/res/layout/activity_definicoes_admin.xml b/app/src/main/res/layout/activity_definicoes_admin.xml
new file mode 100644
index 0000000..e06a978
--- /dev/null
+++ b/app/src/main/res/layout/activity_definicoes_admin.xml
@@ -0,0 +1,131 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_detalhes_reservas.xml b/app/src/main/res/layout/activity_detalhes_reservas.xml
index 5e6d13e..ffb9d06 100644
--- a/app/src/main/res/layout/activity_detalhes_reservas.xml
+++ b/app/src/main/res/layout/activity_detalhes_reservas.xml
@@ -125,7 +125,7 @@
android:id="@+id/btnConfirmarReserva"
android:layout_width="0dp"
android:layout_height="wrap_content"
- android:layout_marginEnd="8dp"
+ android:layout_marginEnd="4dp"
android:layout_weight="1"
android:background="@drawable/btn_primary"
android:text="Confirmar"
@@ -136,12 +136,24 @@
android:id="@+id/btnCancelarReserva"
android:layout_width="0dp"
android:layout_height="wrap_content"
- android:layout_marginStart="8dp"
+ android:layout_marginHorizontal="4dp"
android:layout_weight="1"
android:background="@drawable/btn_light_border"
- android:text="Cancelar"
+ android:text="Recusar"
android:textAllCaps="false"
android:textColor="#00001A" />
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_relatorios.xml b/app/src/main/res/layout/activity_relatorios.xml
deleted file mode 100644
index 70686b4..0000000
--- a/app/src/main/res/layout/activity_relatorios.xml
+++ /dev/null
@@ -1,53 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/item_food_category.xml b/app/src/main/res/layout/item_food_category.xml
new file mode 100644
index 0000000..d4ffac3
--- /dev/null
+++ b/app/src/main/res/layout/item_food_category.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 5b6ad9b..416341a 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,7 @@
-#Tue Jan 20 14:11:23 WET 2026
+#Tue Feb 24 17:05:40 WET 2026
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
+distributionSha256Sum=a17ddd85a26b6a7f5ddb71ff8b05fc5104c0202c6e64782429790c933686c806
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists