From 2db654428489f3e78a06dd59d0725fe284b4403d Mon Sep 17 00:00:00 2001
From: 230409 <230409@epvc.pt>
Date: Tue, 17 Mar 2026 09:16:58 +0000
Subject: [PATCH] ...
---
app/build.gradle.kts | 2 +
app/src/main/AndroidManifest.xml | 10 +
.../pap_teste/CheckInAntecipadoActivity.java | 92 +++++++--
.../pap_teste/ClientDashboardActivity.java | 7 +
.../pap_teste/DefinicoesAdminActivity.java | 47 +++--
.../pap_teste/DetalhesReservasActivity.java | 115 ++++++-----
.../EstablishmentDashboardActivity.java | 6 +-
.../ExplorarRestaurantesActivity.java | 193 +++++++++++++++---
.../example/pap_teste/FavoritosActivity.java | 6 +-
.../com/example/pap_teste/MainActivity.java | 55 ++---
.../pap_teste/NovaReservaActivity.java | 165 ++++++++++++++-
.../pap_teste/ProfileDashboardActivity.java | 81 +++++++-
.../layout/activity_checkin_antecipado.xml | 30 ++-
.../res/layout/activity_client_dashboard.xml | 24 +++
.../res/layout/activity_definicoes_admin.xml | 27 ++-
.../layout/activity_explorar_restaurantes.xml | 101 +++++++++
.../main/res/layout/activity_nova_reserva.xml | 25 +++
.../res/layout/activity_profile_dashboard.xml | 4 +-
.../main/res/layout/item_food_category.xml | 37 ++--
gradle/libs.versions.toml | 4 +
20 files changed, 848 insertions(+), 183 deletions(-)
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index ed1e5f2..ad20d54 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -42,6 +42,8 @@ dependencies {
implementation("com.google.firebase:firebase-firestore")
implementation("com.google.firebase:firebase-auth")
implementation(libs.firebase.database)
+ implementation(libs.glide)
+ implementation(libs.firebase.storage)
testImplementation(libs.junit)
androidTestImplementation(libs.ext.junit)
androidTestImplementation(libs.espresso.core)
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 7cab3cb..4449370 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -6,6 +6,11 @@
+
+
+
+
+
+
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 25f826c..982bb43 100644
--- a/app/src/main/java/com/example/pap_teste/CheckInAntecipadoActivity.java
+++ b/app/src/main/java/com/example/pap_teste/CheckInAntecipadoActivity.java
@@ -2,10 +2,12 @@ package com.example.pap_teste;
import android.Manifest;
import android.content.Context;
+import android.content.Intent;
import android.content.pm.PackageManager;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
+import android.os.Build;
import android.os.Bundle;
import android.widget.Button;
import android.widget.TextView;
@@ -25,16 +27,20 @@ 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 CheckInAntecipadoActivity extends AppCompatActivity implements LocationListener {
- private TextView txtDistancia, txtStatus;
- private Button btnConfirmarChegada;
+ private TextView txtDistancia, txtStatus, txtEndereco;
+ private Button btnConfirmarChegada, btnAbrirMapa;
private LocationManager locationManager;
private DatabaseReference databaseReference;
private double restaurantLat, restaurantLon;
private int securityDistance = 500; // default 500m
private boolean settingsLoaded = false;
+ private String restaurantAddress;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -49,7 +55,9 @@ public class CheckInAntecipadoActivity extends AppCompatActivity implements Loca
txtDistancia = findViewById(R.id.txtDistancia);
txtStatus = findViewById(R.id.txtStatusDistancia);
+ txtEndereco = findViewById(R.id.txtEnderecoRestaurante);
btnConfirmarChegada = findViewById(R.id.btnConfirmarChegada);
+ btnAbrirMapa = findViewById(R.id.btnAbrirMapa);
Button back = findViewById(R.id.btnVoltar);
if (back != null) {
@@ -65,12 +73,37 @@ public class CheckInAntecipadoActivity extends AppCompatActivity implements Loca
}
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
- startLocationUpdates();
+ if (hasRequiredPermissions()) {
+ startLocationUpdates();
+ } else {
+ txtStatus.setText("Permissões em falta para localização/proximidade.");
+ }
btnConfirmarChegada.setOnClickListener(v -> {
Toast.makeText(this, "Chegada confirmada com sucesso!", Toast.LENGTH_LONG).show();
finish();
});
+
+ btnAbrirMapa.setOnClickListener(v -> {
+ if (restaurantAddress != null) {
+ try {
+ String uri = "geo:0,0?q=" + java.net.URLEncoder.encode(restaurantAddress, "UTF-8");
+ Intent intent = new Intent(Intent.ACTION_VIEW, android.net.Uri.parse(uri));
+ startActivity(intent);
+ } catch (Exception e) {
+ Toast.makeText(this, "Erro ao abrir mapa.", Toast.LENGTH_SHORT).show();
+ }
+ }
+ });
+ }
+
+ private boolean hasRequiredPermissions() {
+ boolean fineLocation = ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+ boolean btScan = ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_SCAN) == PackageManager.PERMISSION_GRANTED;
+ return fineLocation && btScan;
+ }
+ return fineLocation;
}
private void loadRestaurantSettings(String restaurantId) {
@@ -79,17 +112,26 @@ public class CheckInAntecipadoActivity extends AppCompatActivity implements Loca
@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);
+ restaurantAddress = snapshot.child("address").getValue(String.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;
+
+ if (restaurantAddress != null) {
+ txtEndereco.setText("Morada: " + restaurantAddress);
+ geocodeAddress(restaurantAddress);
+ } else {
+ txtEndereco.setText("Morada não disponível.");
+ // Fallback to old lat/lon if they exist
+ Double lat = snapshot.child("latitude").getValue(Double.class);
+ Double lon = snapshot.child("longitude").getValue(Double.class);
+ if (lat != null && lon != null) {
+ restaurantLat = lat;
+ restaurantLon = lon;
+ settingsLoaded = true;
+ }
+ }
} else {
- txtStatus.setText("Aviso: Definições do restaurante não encontradas. Usando valores padrão.");
- settingsLoaded = true; // Use defaults
+ txtStatus.setText("Aviso: Definições do restaurante não encontradas.");
}
}
@@ -100,12 +142,26 @@ public class CheckInAntecipadoActivity extends AppCompatActivity implements Loca
});
}
+ private void geocodeAddress(String address) {
+ new Thread(() -> {
+ try {
+ android.location.Geocoder geocoder = new android.location.Geocoder(this);
+ List addresses = geocoder.getFromLocationName(address, 1);
+ if (addresses != null && !addresses.isEmpty()) {
+ restaurantLat = addresses.get(0).getLatitude();
+ restaurantLon = addresses.get(0).getLongitude();
+ settingsLoaded = true;
+ } else {
+ runOnUiThread(() -> txtStatus.setText("Erro: Não foi possível localizar a morada no mapa."));
+ }
+ } catch (Exception e) {
+ runOnUiThread(() -> txtStatus.setText("Erro ao obter coordenadas da morada."));
+ }
+ }).start();
+ }
+
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.");
+ if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
try {
@@ -143,7 +199,9 @@ public class CheckInAntecipadoActivity extends AppCompatActivity implements Loca
@Override
protected void onStop() {
super.onStop();
- locationManager.removeUpdates(this);
+ if (locationManager != null) {
+ locationManager.removeUpdates(this);
+ }
}
@Override
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 d4ff8a9..d371d00 100644
--- a/app/src/main/java/com/example/pap_teste/ClientDashboardActivity.java
+++ b/app/src/main/java/com/example/pap_teste/ClientDashboardActivity.java
@@ -99,5 +99,12 @@ public class ClientDashboardActivity extends AppCompatActivity {
findViewById(R.id.btnNovaReserva)
.setOnClickListener(v -> startActivity(new Intent(this, NovaReservaActivity.class)));
+
+ findViewById(R.id.btnMinhasReservas)
+ .setOnClickListener(v -> {
+ Intent intent = new Intent(this, MinhasReservasActivity.class);
+ intent.putExtra(MainActivity.EXTRA_EMAIL, email);
+ startActivity(intent);
+ });
}
}
diff --git a/app/src/main/java/com/example/pap_teste/DefinicoesAdminActivity.java b/app/src/main/java/com/example/pap_teste/DefinicoesAdminActivity.java
index 7acce4e..61c9584 100644
--- a/app/src/main/java/com/example/pap_teste/DefinicoesAdminActivity.java
+++ b/app/src/main/java/com/example/pap_teste/DefinicoesAdminActivity.java
@@ -24,9 +24,11 @@ import java.util.Map;
public class DefinicoesAdminActivity extends AppCompatActivity {
- private EditText inputRadius, inputLatitude, inputLongitude;
+ private EditText inputRadius, inputAddress;
+ private android.widget.Spinner spinnerCategory;
private DatabaseReference databaseReference;
private String documentId;
+ private String[] categories = {"Carnes", "Massas", "Sushi", "Pizzas", "Sobremesas"};
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -47,8 +49,14 @@ public class DefinicoesAdminActivity extends AppCompatActivity {
databaseReference = FirebaseDatabase.getInstance().getReference().child("users");
inputRadius = findViewById(R.id.inputRadius);
- inputLatitude = findViewById(R.id.inputLatitude);
- inputLongitude = findViewById(R.id.inputLongitude);
+ inputAddress = findViewById(R.id.inputAddress);
+ spinnerCategory = findViewById(R.id.spinnerCategory);
+
+ 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);
@@ -73,13 +81,20 @@ public class DefinicoesAdminActivity extends AppCompatActivity {
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("address")) {
+ String addr = snapshot.child("address").getValue(String.class);
+ inputAddress.setText(addr != null ? addr : "");
}
- if (snapshot.hasChild("longitude")) {
- Object val = snapshot.child("longitude").getValue();
- inputLongitude.setText(val != null ? val.toString() : "");
+ 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;
+ }
+ }
+ }
}
}
}
@@ -96,23 +111,21 @@ public class DefinicoesAdminActivity extends AppCompatActivity {
return;
String radiusStr = inputRadius.getText().toString().trim();
- String latStr = inputLatitude.getText().toString().trim();
- String lonStr = inputLongitude.getText().toString().trim();
+ String addressStr = inputAddress.getText().toString().trim();
+ String selectedCategory = spinnerCategory.getSelectedItem().toString();
- if (TextUtils.isEmpty(radiusStr) || TextUtils.isEmpty(latStr) || TextUtils.isEmpty(lonStr)) {
+ 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);
- 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);
+ updates.put("address", addressStr);
+ updates.put("category", selectedCategory);
databaseReference.child(documentId).updateChildren(updates)
.addOnSuccessListener(aVoid -> {
@@ -123,7 +136,7 @@ public class DefinicoesAdminActivity extends AppCompatActivity {
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();
+ 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
index 2fa0d74..79fc1ad 100644
--- a/app/src/main/java/com/example/pap_teste/DetalhesReservasActivity.java
+++ b/app/src/main/java/com/example/pap_teste/DetalhesReservasActivity.java
@@ -18,7 +18,7 @@ import java.util.List;
public class DetalhesReservasActivity extends AppCompatActivity {
- private final List reservas = new ArrayList<>();
+ private final List reservas = new ArrayList<>();
private ArrayAdapter adapter;
private ListView listReservas;
private TextView txtInfo;
@@ -27,6 +27,8 @@ public class DetalhesReservasActivity extends AppCompatActivity {
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) {
@@ -39,10 +41,14 @@ public class DetalhesReservasActivity extends AppCompatActivity {
return insets;
});
+ restaurantEmail = getIntent().getStringExtra(MainActivity.EXTRA_EMAIL);
+ if (restaurantEmail == null)
+ restaurantEmail = "sabor_arte@restaurante.com";
+
bindViews();
- seedReservasDemo();
setupList();
setupActions();
+ loadReservas();
}
private void bindViews() {
@@ -62,17 +68,36 @@ public class DetalhesReservasActivity extends AppCompatActivity {
}
}
- private void seedReservasDemo() {
- 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 loadReservas() {
+ databaseReference = com.google.firebase.database.FirebaseDatabase.getInstance().getReference("reservas");
+ databaseReference.orderByChild("restauranteEmail").equalTo(restaurantEmail)
+ .addValueEventListener(new com.google.firebase.database.ValueEventListener() {
+ @Override
+ public void onDataChange(
+ @androidx.annotation.NonNull com.google.firebase.database.DataSnapshot snapshot) {
+ reservas.clear();
+ 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) {
+ 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);
- refreshList();
listReservas.setOnItemClickListener((parent, view, position, id) -> {
selectedIndex = position;
@@ -83,10 +108,10 @@ public class DetalhesReservasActivity extends AppCompatActivity {
private void setupActions() {
if (btnConfirmar != null) {
btnConfirmar.setOnClickListener(v -> {
- ReservaItem item = reservas.get(selectedIndex);
- if ("Pendente".equals(item.estado)) {
+ com.example.pap_teste.models.Reserva item = reservas.get(selectedIndex);
+ if ("Pendente".equals(item.getEstado())) {
atualizarEstadoSelecionado("Confirmada");
- } else if ("Confirmada".equals(item.estado)) {
+ } else if ("Confirmada".equals(item.getEstado())) {
atualizarEstadoSelecionado("Concluída");
}
});
@@ -123,14 +148,17 @@ public class DetalhesReservasActivity extends AppCompatActivity {
.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();
+ String idReserva = reservas.get(selectedIndex).getId();
+ databaseReference.child(idReserva).removeValue().addOnCompleteListener(task -> {
+ if (task.isSuccessful()) {
+ selectedIndex = -1;
+ txtInfo.setText("Selecione uma reserva");
+ txtNotas.setText("");
+ txtEstado.setText("Estado:");
+ txtMensagem.setText("Reserva apagada com sucesso.");
+ toggleButtons(null);
+ }
+ });
})
.setNegativeButton("Voltar", null)
.show();
@@ -142,21 +170,25 @@ public class DetalhesReservasActivity extends AppCompatActivity {
return;
}
- ReservaItem item = reservas.get(selectedIndex);
- item.estado = novoEstado;
- txtMensagem.setText(String.format("Reserva de %s marcada como %s.", item.nomeCliente, novoEstado));
- mostrarDetalhe(item);
- refreshList();
+ 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(ReservaItem item) {
- 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));
+ 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(ReservaItem 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);
@@ -164,7 +196,7 @@ public class DetalhesReservasActivity extends AppCompatActivity {
return;
}
- switch (item.estado) {
+ switch (item.getEstado()) {
case "Pendente":
btnConfirmar.setText("Confirmar");
btnConfirmar.setVisibility(android.view.View.VISIBLE);
@@ -192,28 +224,11 @@ public class DetalhesReservasActivity extends AppCompatActivity {
private void refreshList() {
adapter.clear();
- for (ReservaItem item : reservas) {
- String resumo = String.format("%s - %s (%s) • %s", item.hora, item.mesa, item.estado, item.nomeCliente);
+ 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();
}
-
- private static class ReservaItem {
- String nomeCliente;
- String mesa;
- String hora;
- int pessoas;
- String notas;
- String estado;
-
- ReservaItem(String nomeCliente, String mesa, String hora, int pessoas, String notas, String estado) {
- this.nomeCliente = nomeCliente;
- this.mesa = mesa;
- this.hora = hora;
- this.pessoas = pessoas;
- this.notas = notas;
- this.estado = estado;
- }
- }
}
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 af69294..c14b834 100644
--- a/app/src/main/java/com/example/pap_teste/EstablishmentDashboardActivity.java
+++ b/app/src/main/java/com/example/pap_teste/EstablishmentDashboardActivity.java
@@ -52,7 +52,11 @@ public class EstablishmentDashboardActivity extends AppCompatActivity {
btnGerirMesas.setOnClickListener(v -> startActivity(new Intent(this, GerirMesasActivity.class)));
- btnDetails.setOnClickListener(v -> startActivity(new Intent(this, DetalhesReservasActivity.class)));
+ btnDetails.setOnClickListener(v -> {
+ Intent intent = new Intent(this, DetalhesReservasActivity.class);
+ intent.putExtra(MainActivity.EXTRA_EMAIL, getIntent().getStringExtra(MainActivity.EXTRA_EMAIL));
+ startActivity(intent);
+ });
btnSettings.setOnClickListener(v -> {
Intent intent = new Intent(this, DefinicoesAdminActivity.class);
diff --git a/app/src/main/java/com/example/pap_teste/ExplorarRestaurantesActivity.java b/app/src/main/java/com/example/pap_teste/ExplorarRestaurantesActivity.java
index ee44498..e83cbc3 100644
--- a/app/src/main/java/com/example/pap_teste/ExplorarRestaurantesActivity.java
+++ b/app/src/main/java/com/example/pap_teste/ExplorarRestaurantesActivity.java
@@ -12,6 +12,21 @@ import android.widget.Button;
public class ExplorarRestaurantesActivity extends AppCompatActivity {
+ private enum State {
+ LIST, DETAILS
+ }
+
+ private State currentState = State.LIST;
+ private com.example.pap_teste.models.Restaurant selectedRestaurant = null;
+
+ private android.view.View scrollReservaDetails;
+ private androidx.recyclerview.widget.RecyclerView rvRestaurants;
+ private android.widget.TextView txtTitle;
+
+ private String selectedDate = null;
+ private String selectedTime = null;
+ private int selectedPartySize = 0;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -23,44 +38,168 @@ public class ExplorarRestaurantesActivity extends AppCompatActivity {
return insets;
});
+ rvRestaurants = findViewById(R.id.rvRestaurants);
+ scrollReservaDetails = findViewById(R.id.scrollReservaDetails);
+ txtTitle = findViewById(R.id.txtTituloExplorar);
+
Button back = findViewById(R.id.btnVoltar);
if (back != null) {
- back.setOnClickListener(v -> finish());
+ back.setOnClickListener(v -> handleBackNavigation());
}
setupRestaurantList();
+ updateViewState();
+ }
+
+ private void handleBackNavigation() {
+ if (currentState == State.DETAILS) {
+ currentState = State.LIST;
+ updateViewState();
+ } else {
+ finish();
+ }
+ }
+
+ private void updateViewState() {
+ rvRestaurants.setVisibility(currentState == State.LIST ? android.view.View.VISIBLE : android.view.View.GONE);
+ scrollReservaDetails
+ .setVisibility(currentState == State.DETAILS ? android.view.View.VISIBLE : android.view.View.GONE);
+
+ if (currentState == State.LIST) {
+ String filter = getIntent().getStringExtra("category_filter");
+ txtTitle.setText(filter != null ? "Explorar: " + filter : "Explorar restaurantes");
+ } else {
+ txtTitle.setText("Reserva: " + (selectedRestaurant != null ? selectedRestaurant.getName() : ""));
+ setupReservationOptions();
+ }
}
private void setupRestaurantList() {
String filter = getIntent().getStringExtra("category_filter");
- android.widget.TextView txtTitle = findViewById(R.id.txtTituloExplorar);
- if (filter != null && txtTitle != null) {
- txtTitle.setText("Explorar: " + filter);
- }
-
- androidx.recyclerview.widget.RecyclerView rv = findViewById(R.id.rvRestaurants);
- java.util.List allRestaurants = new java.util.ArrayList<>();
- allRestaurants.add(new com.example.pap_teste.models.Restaurant("Sabor & Arte", "Tradicional", true));
- allRestaurants.add(new com.example.pap_teste.models.Restaurant("Pizzeria Bella", "Pizzas", false));
- allRestaurants.add(new com.example.pap_teste.models.Restaurant("Sushi Zen", "Sushi", false));
- allRestaurants.add(new com.example.pap_teste.models.Restaurant("O Chuveiro", "Frutos do Mar", true));
- allRestaurants.add(new com.example.pap_teste.models.Restaurant("Hamburgueria Real", "Carnes", false));
- allRestaurants.add(new com.example.pap_teste.models.Restaurant("Churrascaria Gaúcha", "Carnes", false));
- allRestaurants.add(new com.example.pap_teste.models.Restaurant("Sushi House", "Sushi", false));
- allRestaurants.add(new com.example.pap_teste.models.Restaurant("Doce Momento", "Sobremesas", false));
-
- java.util.List filteredList = new java.util.ArrayList<>();
+ java.util.List restaurantsList = new java.util.ArrayList<>();
+ com.google.firebase.database.DatabaseReference usersRef = com.google.firebase.database.FirebaseDatabase.getInstance().getReference("users");
+
+ com.google.firebase.database.Query query = usersRef;
if (filter != null) {
- for (com.example.pap_teste.models.Restaurant r : allRestaurants) {
- if (r.getCategory().equalsIgnoreCase(filter)) {
- filteredList.add(r);
- }
- }
- } else {
- filteredList.addAll(allRestaurants);
+ query = usersRef.orderByChild("category").equalTo(filter);
}
- RestaurantAdapter adapter = new RestaurantAdapter(filteredList);
- rv.setAdapter(adapter);
+ query.addListenerForSingleValueEvent(new com.google.firebase.database.ValueEventListener() {
+ @Override
+ public void onDataChange(@androidx.annotation.NonNull com.google.firebase.database.DataSnapshot snapshot) {
+ restaurantsList.clear();
+ for (com.google.firebase.database.DataSnapshot ds : snapshot.getChildren()) {
+ String role = ds.child("role").getValue(String.class);
+ String accountType = ds.child("accountType").getValue(String.class);
+
+ if ("ADMIN".equalsIgnoreCase(role) || "ESTABELECIMENTO".equalsIgnoreCase(accountType)) {
+ String name = ds.child("establishmentName").getValue(String.class);
+ if (name == null) name = ds.child("displayName").getValue(String.class);
+ String email = ds.child("email").getValue(String.class);
+ String cat = ds.child("category").getValue(String.class);
+
+ // If no category filter in query, we might need a client-side filter if the index isn't used
+ // but here we use the query. Actually if filter is null we get all, but we need to ensure they are ESTAB
+ if (name != null && email != null) {
+ restaurantsList.add(new com.example.pap_teste.models.Restaurant(name, cat, email, false));
+ }
+ }
+ }
+
+ RestaurantAdapter adapter = new RestaurantAdapter(restaurantsList, restaurant -> {
+ selectedRestaurant = restaurant;
+ currentState = State.DETAILS;
+ updateViewState();
+ });
+ rvRestaurants.setAdapter(adapter);
+ }
+
+ @Override
+ public void onCancelled(@androidx.annotation.NonNull com.google.firebase.database.DatabaseError error) {
+ android.widget.Toast.makeText(ExplorarRestaurantesActivity.this, "Erro ao carregar restaurantes.", android.widget.Toast.LENGTH_SHORT).show();
+ }
+ });
+ }
+
+ private void setupReservationOptions() {
+ // Dates
+ androidx.recyclerview.widget.RecyclerView rvDates = findViewById(R.id.rvDates);
+ java.util.List dates = new java.util.ArrayList<>();
+ dates.add("Hoje");
+ dates.add("Amanhã");
+ dates.add("Quarta, 12 Mar");
+ dates.add("Quinta, 13 Mar");
+ dates.add("Sexta, 14 Mar");
+ rvDates.setAdapter(new ReservationOptionAdapter(dates, date -> selectedDate = date));
+
+ // Times
+ androidx.recyclerview.widget.RecyclerView rvTimes = findViewById(R.id.rvTimes);
+ java.util.List times = new java.util.ArrayList<>();
+ times.add("12:00");
+ times.add("13:00");
+ times.add("19:00");
+ times.add("20:00");
+ times.add("21:00");
+ times.add("22:00");
+ rvTimes.setAdapter(new ReservationOptionAdapter(times, time -> selectedTime = time));
+
+ // Party Size
+ androidx.recyclerview.widget.RecyclerView rvParty = findViewById(R.id.rvPartySize);
+ java.util.List party = new java.util.ArrayList<>();
+ party.add("1 pessoa");
+ party.add("2 pessoas");
+ party.add("3 pessoas");
+ party.add("4 pessoas");
+ party.add("5 pessoas");
+ party.add("6+ pessoas");
+ rvParty.setAdapter(new ReservationOptionAdapter(party, size -> {
+ try {
+ selectedPartySize = Integer.parseInt(size.split(" ")[0].replace("+", ""));
+ } catch (Exception e) {
+ selectedPartySize = 6;
+ }
+ }));
+
+ findViewById(R.id.btnConfirmarReserva).setOnClickListener(v -> saveReservation());
+ }
+
+ private void saveReservation() {
+ if (selectedDate == null || selectedTime == null || selectedPartySize == 0) {
+ android.widget.Toast.makeText(this, "Por favor, selecione data, hora e número de pessoas.",
+ android.widget.Toast.LENGTH_SHORT).show();
+ return;
+ }
+
+ String userEmail = com.google.firebase.auth.FirebaseAuth.getInstance().getCurrentUser() != null
+ ? com.google.firebase.auth.FirebaseAuth.getInstance().getCurrentUser().getEmail()
+ : "cliente@teste.com";
+
+ com.google.firebase.database.DatabaseReference ref = com.google.firebase.database.FirebaseDatabase.getInstance()
+ .getReference("reservas");
+ String id = ref.push().getKey();
+
+ com.example.pap_teste.models.Reserva reserva = new com.example.pap_teste.models.Reserva(
+ id,
+ userEmail,
+ selectedRestaurant.getName(),
+ selectedRestaurant.getEmail(),
+ selectedDate,
+ selectedTime,
+ selectedPartySize,
+ "Pendente");
+
+ if (id != null) {
+ ref.child(id).setValue(reserva).addOnCompleteListener(task -> {
+ if (task.isSuccessful()) {
+ android.widget.Toast
+ .makeText(this, "Reserva solicitada com sucesso!", android.widget.Toast.LENGTH_SHORT)
+ .show();
+ finish();
+ } else {
+ android.widget.Toast.makeText(this, "Erro ao salvar reserva.", android.widget.Toast.LENGTH_SHORT)
+ .show();
+ }
+ });
+ }
}
}
diff --git a/app/src/main/java/com/example/pap_teste/FavoritosActivity.java b/app/src/main/java/com/example/pap_teste/FavoritosActivity.java
index 4990ef4..b243ba8 100644
--- a/app/src/main/java/com/example/pap_teste/FavoritosActivity.java
+++ b/app/src/main/java/com/example/pap_teste/FavoritosActivity.java
@@ -34,10 +34,10 @@ public class FavoritosActivity extends AppCompatActivity {
private void setupFavoritesList() {
androidx.recyclerview.widget.RecyclerView rv = findViewById(R.id.rvFavoritos);
java.util.List list = new java.util.ArrayList<>();
- list.add(new com.example.pap_teste.models.Restaurant("Sabor & Arte", "Tradicional", true));
- list.add(new com.example.pap_teste.models.Restaurant("O Chuveiro", "Mariscos", true));
+ list.add(new com.example.pap_teste.models.Restaurant("Sabor & Arte", "Tradicional", "sabor_arte@restaurante.com", true));
+ list.add(new com.example.pap_teste.models.Restaurant("O Chuveiro", "Mariscos", "chuveiro@restaurante.com", true));
- RestaurantAdapter adapter = new RestaurantAdapter(list);
+ RestaurantAdapter adapter = new RestaurantAdapter(list, null);
rv.setAdapter(adapter);
}
}
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 fa462b5..c59057c 100644
--- a/app/src/main/java/com/example/pap_teste/MainActivity.java
+++ b/app/src/main/java/com/example/pap_teste/MainActivity.java
@@ -19,6 +19,7 @@ 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;
@@ -28,7 +29,9 @@ 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;
public class MainActivity extends AppCompatActivity {
@@ -68,16 +71,16 @@ public class MainActivity extends AppCompatActivity {
private FirebaseAuth firebaseAuth;
private DatabaseReference databaseReference;
- private final ActivityResultLauncher locationPermissionRequest = registerForActivityResult(
+ private final ActivityResultLauncher permissionRequest = 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);
+ 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 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();
@@ -103,26 +106,32 @@ public class MainActivity extends AppCompatActivity {
setupTypeToggle();
setupActionToggle();
setupPrimaryAction();
- checkLocationPermissions();
+ checkPermissions();
}
- private void checkLocationPermissions() {
- if (ContextCompat.checkSelfPermission(this,
- Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
+ 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 (!permissionsNeeded.isEmpty()) {
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();
+ .setTitle("Permissões Necessárias")
+ .setMessage("Para o correto funcionamento do check-in e serviços de proximidade, precisamos de algumas permissões.")
+ .setPositiveButton("Configurar", (dialog, which) -> {
+ permissionRequest.launch(permissionsNeeded.toArray(new String[0]));
})
+ .setNegativeButton("Agora Não", null)
.show();
}
}
diff --git a/app/src/main/java/com/example/pap_teste/NovaReservaActivity.java b/app/src/main/java/com/example/pap_teste/NovaReservaActivity.java
index a6a30f8..0d9736a 100644
--- a/app/src/main/java/com/example/pap_teste/NovaReservaActivity.java
+++ b/app/src/main/java/com/example/pap_teste/NovaReservaActivity.java
@@ -13,6 +13,18 @@ import android.widget.Button;
public class NovaReservaActivity extends AppCompatActivity {
+ private enum State {
+ CATEGORIES, RESTAURANTS, DETAILS
+ }
+
+ private State currentState = State.CATEGORIES;
+ private String selectedCategory = null;
+ private com.example.pap_teste.models.Restaurant selectedRestaurant = null;
+
+ private androidx.recyclerview.widget.RecyclerView rvCategories, rvRestaurants;
+ private android.view.View scrollNovaReserva;
+ private android.widget.TextView txtTitle;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -24,14 +36,110 @@ public class NovaReservaActivity extends AppCompatActivity {
return insets;
});
+ rvCategories = findViewById(R.id.rvCategories);
+ rvRestaurants = findViewById(R.id.rvRestaurants);
+ scrollNovaReserva = findViewById(R.id.scrollNovaReserva);
+ txtTitle = findViewById(R.id.txtTituloNovaReserva);
+
Button back = findViewById(R.id.btnVoltar);
if (back != null) {
- back.setOnClickListener(v -> finish());
+ back.setOnClickListener(v -> handleBackNavigation());
}
- setupReservationOptions();
+ setupCategories();
+ updateViewState();
}
+ private void handleBackNavigation() {
+ if (currentState == State.RESTAURANTS) {
+ currentState = State.CATEGORIES;
+ updateViewState();
+ } else if (currentState == State.DETAILS) {
+ currentState = State.RESTAURANTS;
+ updateViewState();
+ } else {
+ finish();
+ }
+ }
+
+ private void updateViewState() {
+ rvCategories
+ .setVisibility(currentState == State.CATEGORIES ? android.view.View.VISIBLE : android.view.View.GONE);
+ rvRestaurants
+ .setVisibility(currentState == State.RESTAURANTS ? android.view.View.VISIBLE : android.view.View.GONE);
+ scrollNovaReserva
+ .setVisibility(currentState == State.DETAILS ? android.view.View.VISIBLE : android.view.View.GONE);
+
+ if (currentState == State.CATEGORIES) {
+ txtTitle.setText("Escolha o tema");
+ } else if (currentState == State.RESTAURANTS) {
+ txtTitle.setText("Restaurantes: " + selectedCategory);
+ } else {
+ txtTitle.setText("Reserva: " + (selectedRestaurant != null ? selectedRestaurant.getName() : ""));
+ setupReservationOptions();
+ }
+ }
+
+ private void setupCategories() {
+ java.util.List cats = new java.util.ArrayList<>();
+ cats.add(new com.example.pap_teste.models.FoodCategory("Carnes", R.drawable.cat_carnes));
+ cats.add(new com.example.pap_teste.models.FoodCategory("Massas", R.drawable.cat_massas));
+ cats.add(new com.example.pap_teste.models.FoodCategory("Sushi", R.drawable.cat_sushi));
+ cats.add(new com.example.pap_teste.models.FoodCategory("Pizzas", R.drawable.cat_pizzas));
+ cats.add(new com.example.pap_teste.models.FoodCategory("Sobremesas", R.drawable.cat_sobremesas));
+
+ rvCategories.setLayoutManager(new androidx.recyclerview.widget.LinearLayoutManager(this));
+ rvCategories.setAdapter(new FoodCategoryAdapter(cats, category -> {
+ selectedCategory = category.getName();
+ currentState = State.RESTAURANTS;
+ setupRestaurants();
+ updateViewState();
+ }));
+ }
+
+ private void setupRestaurants() {
+ java.util.List filteredList = new java.util.ArrayList<>();
+ com.google.firebase.database.DatabaseReference usersRef = com.google.firebase.database.FirebaseDatabase.getInstance().getReference("users");
+
+ usersRef.orderByChild("category").equalTo(selectedCategory).addListenerForSingleValueEvent(new com.google.firebase.database.ValueEventListener() {
+ @Override
+ public void onDataChange(@androidx.annotation.NonNull com.google.firebase.database.DataSnapshot snapshot) {
+ filteredList.clear();
+ for (com.google.firebase.database.DataSnapshot ds : snapshot.getChildren()) {
+ String role = ds.child("role").getValue(String.class);
+ String accountType = ds.child("accountType").getValue(String.class);
+
+ if ("ADMIN".equalsIgnoreCase(role) || "ESTABELECIMENTO".equalsIgnoreCase(accountType)) {
+ String name = ds.child("establishmentName").getValue(String.class);
+ if (name == null) name = ds.child("displayName").getValue(String.class);
+ String email = ds.child("email").getValue(String.class);
+ String cat = ds.child("category").getValue(String.class);
+
+ if (name != null && email != null) {
+ filteredList.add(new com.example.pap_teste.models.Restaurant(name, cat, email, false));
+ }
+ }
+ }
+
+ rvRestaurants.setLayoutManager(new androidx.recyclerview.widget.LinearLayoutManager(NovaReservaActivity.this));
+ rvRestaurants.setAdapter(new RestaurantAdapter(filteredList, restaurant -> {
+ selectedRestaurant = restaurant;
+ currentState = State.DETAILS;
+ updateViewState();
+ }));
+ }
+
+ @Override
+ public void onCancelled(@androidx.annotation.NonNull com.google.firebase.database.DatabaseError error) {
+ android.widget.Toast.makeText(NovaReservaActivity.this, "Erro ao carregar restaurantes.", android.widget.Toast.LENGTH_SHORT).show();
+ }
+ });
+ }
+
+ private String selectedDate = null;
+ private String selectedTime = null;
+ private int selectedPartySize = 0;
+
private void setupReservationOptions() {
// Dates
RecyclerView rvDates = findViewById(R.id.rvDates);
@@ -41,7 +149,7 @@ public class NovaReservaActivity extends AppCompatActivity {
dates.add("Quarta, 12 Mar");
dates.add("Quinta, 13 Mar");
dates.add("Sexta, 14 Mar");
- rvDates.setAdapter(new ReservationOptionAdapter(dates));
+ rvDates.setAdapter(new ReservationOptionAdapter(dates, date -> selectedDate = date));
// Times
RecyclerView rvTimes = findViewById(R.id.rvTimes);
@@ -52,7 +160,7 @@ public class NovaReservaActivity extends AppCompatActivity {
times.add("20:00");
times.add("21:00");
times.add("22:00");
- rvTimes.setAdapter(new ReservationOptionAdapter(times));
+ rvTimes.setAdapter(new ReservationOptionAdapter(times, time -> selectedTime = time));
// Party Size
RecyclerView rvParty = findViewById(R.id.rvPartySize);
@@ -63,6 +171,53 @@ public class NovaReservaActivity extends AppCompatActivity {
party.add("4 pessoas");
party.add("5 pessoas");
party.add("6+ pessoas");
- rvParty.setAdapter(new ReservationOptionAdapter(party));
+ rvParty.setAdapter(new ReservationOptionAdapter(party, size -> {
+ try {
+ selectedPartySize = Integer.parseInt(size.split(" ")[0].replace("+", ""));
+ } catch (Exception e) {
+ selectedPartySize = 6;
+ }
+ }));
+
+ findViewById(R.id.btnConfirmarReserva).setOnClickListener(v -> saveReservation());
+ }
+
+ private void saveReservation() {
+ if (selectedDate == null || selectedTime == null || selectedPartySize == 0) {
+ android.widget.Toast.makeText(this, "Por favor, selecione data, hora e número de pessoas.",
+ android.widget.Toast.LENGTH_SHORT).show();
+ return;
+ }
+
+ String userEmail = com.google.firebase.auth.FirebaseAuth.getInstance().getCurrentUser() != null
+ ? com.google.firebase.auth.FirebaseAuth.getInstance().getCurrentUser().getEmail()
+ : "cliente@teste.com";
+ com.google.firebase.database.DatabaseReference ref = com.google.firebase.database.FirebaseDatabase.getInstance()
+ .getReference("reservas");
+ String id = ref.push().getKey();
+
+ com.example.pap_teste.models.Reserva reserva = new com.example.pap_teste.models.Reserva(
+ id,
+ userEmail,
+ selectedRestaurant.getName(),
+ selectedRestaurant.getEmail(),
+ selectedDate,
+ selectedTime,
+ selectedPartySize,
+ "Pendente");
+
+ if (id != null) {
+ ref.child(id).setValue(reserva).addOnCompleteListener(task -> {
+ if (task.isSuccessful()) {
+ android.widget.Toast
+ .makeText(this, "Reserva solicitada com sucesso!", android.widget.Toast.LENGTH_SHORT)
+ .show();
+ finish();
+ } else {
+ android.widget.Toast.makeText(this, "Erro ao salvar reserva.", android.widget.Toast.LENGTH_SHORT)
+ .show();
+ }
+ });
+ }
}
}
diff --git a/app/src/main/java/com/example/pap_teste/ProfileDashboardActivity.java b/app/src/main/java/com/example/pap_teste/ProfileDashboardActivity.java
index ac32dad..21e02e8 100644
--- a/app/src/main/java/com/example/pap_teste/ProfileDashboardActivity.java
+++ b/app/src/main/java/com/example/pap_teste/ProfileDashboardActivity.java
@@ -13,6 +13,13 @@ import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
+import android.view.View;
+import android.net.Uri;
+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 com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
@@ -22,8 +29,9 @@ import java.util.Map;
public class ProfileDashboardActivity extends AppCompatActivity {
private EditText inputName, inputPhone, inputEmailEdit;
- private String email, documentId;
+ private String email, documentId, photoUrl;
private DatabaseReference databaseReference;
+ private ImageView imgProfile;
private androidx.activity.result.ActivityResultLauncher imagePickerLauncher;
@Override
@@ -49,6 +57,7 @@ public class ProfileDashboardActivity extends AppCompatActivity {
inputName = findViewById(R.id.inputProfileName);
inputPhone = findViewById(R.id.inputProfilePhone);
inputEmailEdit = findViewById(R.id.inputProfileEmail);
+ imgProfile = findViewById(R.id.imgProfile);
if (currentName != null) {
inputName.setText(currentName);
@@ -65,17 +74,25 @@ public class ProfileDashboardActivity extends AppCompatActivity {
if (result.getResultCode() == RESULT_OK && result.getData() != null) {
android.net.Uri imageUri = result.getData().getData();
if (imageUri != null) {
- Toast.makeText(this, "Foto selecionada (Simulação: Seria feito o upload)",
- Toast.LENGTH_SHORT).show();
- // In a real app, you'd upload this to Firebase Storage.
+ uploadImageToFirebase(imageUri);
}
}
});
findViewById(R.id.cardProfileBig).setOnClickListener(v -> {
- Intent intent = new Intent(Intent.ACTION_PICK);
- intent.setType("image/*");
- imagePickerLauncher.launch(intent);
+ String[] options = {"Galeria", "URL da Imagem"};
+ androidx.appcompat.app.AlertDialog.Builder builder = new androidx.appcompat.app.AlertDialog.Builder(this);
+ builder.setTitle("Escolher Foto de Perfil");
+ builder.setItems(options, (dialog, which) -> {
+ if (which == 0) {
+ Intent intent = new Intent(Intent.ACTION_PICK);
+ intent.setType("image/*");
+ imagePickerLauncher.launch(intent);
+ } else {
+ showUrlInputDialog();
+ }
+ });
+ builder.show();
});
Button btnSave = findViewById(R.id.btnSaveProfile);
@@ -91,10 +108,32 @@ public class ProfileDashboardActivity extends AppCompatActivity {
});
btnRes.setOnClickListener(v -> {
- startActivity(new Intent(this, DetalhesReservasActivity.class));
+ startActivity(new Intent(this, MinhasReservasActivity.class));
});
}
+ 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);
+ input.setHint("https://exemplo.com/foto.jpg");
+ 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(imgProfile);
+ Toast.makeText(this, "URL definida!", Toast.LENGTH_SHORT).show();
+ }
+ });
+ builder.setNegativeButton("Cancelar", (dialog, which) -> dialog.cancel());
+
+ builder.show();
+ }
+
private void fetchAdditionalProfileData() {
if (documentId == null)
return;
@@ -109,10 +148,33 @@ public class ProfileDashboardActivity extends AppCompatActivity {
String dbEmail = snapshot.child("email").getValue(String.class);
if (dbEmail != null)
inputEmailEdit.setText(dbEmail);
+
+ photoUrl = snapshot.child("photoUrl").getValue(String.class);
+ if (photoUrl != null && !photoUrl.isEmpty()) {
+ Glide.with(this).load(photoUrl).circleCrop().into(imgProfile);
+ }
}
});
}
+ private void uploadImageToFirebase(Uri imageUri) {
+ if (documentId == null)
+ return;
+
+ StorageReference storageRef = FirebaseStorage.getInstance().getReference()
+ .child("profile_pics/" + UUID.randomUUID().toString());
+
+ storageRef.putFile(imageUri).addOnSuccessListener(taskSnapshot -> {
+ storageRef.getDownloadUrl().addOnSuccessListener(uri -> {
+ photoUrl = uri.toString();
+ Glide.with(this).load(photoUrl).circleCrop().into(imgProfile);
+ Toast.makeText(this, "Foto carregada!", Toast.LENGTH_SHORT).show();
+ });
+ }).addOnFailureListener(e -> {
+ Toast.makeText(this, "Falha no upload.", Toast.LENGTH_SHORT).show();
+ });
+ }
+
private void saveProfile() {
if (documentId == null)
return;
@@ -130,6 +192,9 @@ public class ProfileDashboardActivity extends AppCompatActivity {
updates.put("displayName", newName);
updates.put("phone", newPhone);
updates.put("email", newEmail);
+ if (photoUrl != null) {
+ updates.put("photoUrl", photoUrl);
+ }
databaseReference.child(documentId).updateChildren(updates)
.addOnSuccessListener(aVoid -> {
diff --git a/app/src/main/res/layout/activity_checkin_antecipado.xml b/app/src/main/res/layout/activity_checkin_antecipado.xml
index d7e5c7d..e8dcbf9 100644
--- a/app/src/main/res/layout/activity_checkin_antecipado.xml
+++ b/app/src/main/res/layout/activity_checkin_antecipado.xml
@@ -73,16 +73,42 @@
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 ca1ffd3..87753e6 100644
--- a/app/src/main/res/layout/activity_client_dashboard.xml
+++ b/app/src/main/res/layout/activity_client_dashboard.xml
@@ -234,6 +234,30 @@
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_definicoes_admin.xml b/app/src/main/res/layout/activity_definicoes_admin.xml
index e06a978..ad8606d 100644
--- a/app/src/main/res/layout/activity_definicoes_admin.xml
+++ b/app/src/main/res/layout/activity_definicoes_admin.xml
@@ -87,30 +87,35 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
- android:text="Localização do Restaurante"
+ android:text="Informação do Restaurante"
android:textColor="#000"
android:textSize="16sp"
android:textStyle="bold" />
-
+ android:layout_marginTop="12dp"
+ android:text="Categoria"
+ android:textColor="#5F5F5F"
+ android:textSize="14sp" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_nova_reserva.xml b/app/src/main/res/layout/activity_nova_reserva.xml
index ab0c2c1..e17197e 100644
--- a/app/src/main/res/layout/activity_nova_reserva.xml
+++ b/app/src/main/res/layout/activity_nova_reserva.xml
@@ -32,12 +32,37 @@
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginTop="32dp" />
+
+
+
+
+ android:src="@drawable/circle_bg" />
-
-
-
+ android:padding="16dp">
-
+
+
+
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index b31c5ab..8d3d125 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -11,6 +11,8 @@ constraintlayout = "2.2.1"
firebaseBom = "33.7.0"
googleServices = "4.4.2"
firebaseDatabase = "22.0.1"
+glide = "4.16.0"
+firebaseStorage = "21.0.1"
[libraries]
junit = { group = "junit", name = "junit", version.ref = "junit" }
@@ -23,6 +25,8 @@ activity = { group = "androidx.activity", name = "activity", version.ref = "acti
constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" }
firebase-bom = { group = "com.google.firebase", name = "firebase-bom", version.ref = "firebaseBom" }
firebase-database = { group = "com.google.firebase", name = "firebase-database", version.ref = "firebaseDatabase" }
+glide = { group = "com.github.bumptech.glide", name = "glide", version.ref = "glide" }
+firebase-storage = { group = "com.google.firebase", name = "firebase-storage", version.ref = "firebaseStorage" }
[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }