This commit is contained in:
2026-06-09 17:12:07 +01:00
parent 31a7cbb2df
commit d192568ed8
5 changed files with 81 additions and 121 deletions

View File

@@ -14,6 +14,10 @@
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<!-- Notification permissions -->
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<application
android:allowBackup="true"
@@ -113,6 +117,11 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".ReservationNotificationService"
android:exported="false"
android:foregroundServiceType="dataSync" />
</application>
</manifest>

View File

@@ -37,19 +37,17 @@ public class ClientDashboardActivity extends AppCompatActivity {
private TextView txtGreeting;
private ImageView imgProfile;
private EditText etSearch;
private ChipGroup chipGroupCategories;
private RecyclerView rvFeatured, rvMainRestaurants;
private RecyclerView rvFeatured;
private ProgressBar progressBar;
private View layoutFeatured, layoutAllRestaurants;
private View layoutFeatured;
private android.widget.LinearLayout categoriesContainer;
private List<Restaurant> allRestaurants = new ArrayList<>();
private List<Restaurant> filteredRestaurants = new ArrayList<>();
private RestaurantAdapter mainAdapter;
private FeaturedRestaurantAdapter featuredAdapter;
private final String[] CATEGORIES = { "Tudo", "Carnes", "Massas", "Sushi", "Pizzas", "Sobremesas" };
private String currentCategoryFilter = "Tudo";
private final String[] CATEGORIES = { "Carnes", "Massas", "Sushi", "Pizzas", "Sobremesas" };
private String currentSearchFilter = "";
@Override
@@ -70,43 +68,38 @@ public class ClientDashboardActivity extends AppCompatActivity {
initViews();
setupBottomNavigation();
setupSearch();
setupCategories();
updateGreeting();
fetchProfilePicture();
fetchRestaurants();
// Iniciar serviço de notificações se for Android O ou superior
Intent serviceIntent = new Intent(this, ReservationNotificationService.class);
startService(serviceIntent);
}
private RestaurantAdapter.OnRestaurantClickListener clickListener;
private void initViews() {
txtGreeting = findViewById(R.id.txtClientGreeting);
imgProfile = findViewById(R.id.imgProfile);
etSearch = findViewById(R.id.etSearch);
chipGroupCategories = findViewById(R.id.chipGroupCategories);
rvFeatured = findViewById(R.id.rvFeatured);
rvMainRestaurants = findViewById(R.id.rvMainRestaurants);
progressBar = findViewById(R.id.progressBar);
layoutFeatured = findViewById(R.id.layoutFeatured);
layoutAllRestaurants = findViewById(R.id.layoutAllRestaurants);
categoriesContainer = findViewById(R.id.categoriesContainer);
rvFeatured.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false));
rvMainRestaurants.setLayoutManager(new LinearLayoutManager(this));
// Click listener for restaurants to open booking flow
RestaurantAdapter.OnRestaurantClickListener clickListener = restaurant -> {
clickListener = restaurant -> {
Intent intent = new Intent(this, ExplorarRestaurantesActivity.class);
// Reusing existing activity for details if needed, or pass data to
// NovaReservaActivity
// We pass the filter so it can maybe open directly or we just pass restaurant
// email
intent.putExtra("restaurant", restaurant);
startActivity(intent);
};
featuredAdapter = new FeaturedRestaurantAdapter(new ArrayList<>(), clickListener);
mainAdapter = new RestaurantAdapter(filteredRestaurants, clickListener);
rvFeatured.setAdapter(featuredAdapter);
rvMainRestaurants.setAdapter(mainAdapter);
// Click listener for profile picture in the header
findViewById(R.id.cardProfile).setOnClickListener(v -> {
@@ -163,7 +156,7 @@ public class ClientDashboardActivity extends AppCompatActivity {
private void fetchRestaurants() {
progressBar.setVisibility(View.VISIBLE);
layoutFeatured.setVisibility(View.GONE);
layoutAllRestaurants.setVisibility(View.GONE);
categoriesContainer.removeAllViews();
DatabaseReference usersRef = FirebaseDatabase.getInstance().getReference("Restaurantes");
usersRef.addValueEventListener(new ValueEventListener() {
@@ -207,47 +200,6 @@ public class ClientDashboardActivity extends AppCompatActivity {
});
}
private void setupCategories() {
for (String category : CATEGORIES) {
Chip chip = new Chip(this);
chip.setText(category);
chip.setCheckable(true);
chip.setClickable(true);
// Default styling
chip.setChipBackgroundColorResource(R.color.colorSurface);
chip.setTextColor(getResources().getColor(R.color.colorTextSecondary));
chip.setChipStrokeWidth(0f);
if (category.equals("Tudo")) {
chip.setChecked(true);
chip.setChipBackgroundColorResource(R.color.colorPrimary);
chip.setTextColor(getResources().getColor(R.color.white));
}
chip.setOnCheckedChangeListener((buttonView, isChecked) -> {
if (isChecked) {
// Reset all other chips visual state
for (int i = 0; i < chipGroupCategories.getChildCount(); i++) {
Chip c = (Chip) chipGroupCategories.getChildAt(i);
if (c != chip) {
c.setChipBackgroundColorResource(R.color.colorSurface);
c.setTextColor(getResources().getColor(R.color.colorTextSecondary));
}
}
chip.setChipBackgroundColorResource(R.color.colorPrimary);
chip.setTextColor(getResources().getColor(R.color.white));
currentCategoryFilter = category;
applyFilters();
} else if (currentCategoryFilter.equals(category)) {
// Prevent unchecking the currently selected chip
chip.setChecked(true);
}
});
chipGroupCategories.addView(chip);
}
}
private void setupSearch() {
etSearch.addTextChangedListener(new TextWatcher() {
@Override
@@ -271,35 +223,46 @@ public class ClientDashboardActivity extends AppCompatActivity {
String normalizedSearch = normalizeString(currentSearchFilter);
for (Restaurant r : allRestaurants) {
boolean matchesCategory = currentCategoryFilter.equals("Tudo")
|| currentCategoryFilter.equals(r.getCategory());
String normalizedName = normalizeString(r.getName());
boolean matchesSearch = currentSearchFilter.isEmpty() || normalizedName.contains(normalizedSearch);
if (matchesCategory && matchesSearch) {
if (matchesSearch) {
filteredRestaurants.add(r);
}
}
mainAdapter.notifyDataSetChanged();
// Update featured (just the first 3 for demo, or based on a specific logic)
// Update featured carousel with top restaurants
List<Restaurant> featuredList = new ArrayList<>();
for (int i = 0; i < Math.min(3, filteredRestaurants.size()); i++) {
featuredList.add(filteredRestaurants.get(i));
}
featuredAdapter = new FeaturedRestaurantAdapter(featuredList,
mainAdapter instanceof RestaurantAdapter ? restaurant -> {
Intent intent = new Intent(this, ExplorarRestaurantesActivity.class);
intent.putExtra("restaurant", restaurant);
startActivity(intent);
} : null);
featuredAdapter = new FeaturedRestaurantAdapter(featuredList, clickListener);
rvFeatured.setAdapter(featuredAdapter);
layoutFeatured.setVisibility(featuredList.isEmpty() ? View.GONE : View.VISIBLE);
layoutAllRestaurants.setVisibility(filteredRestaurants.isEmpty() ? View.GONE : View.VISIBLE);
// Update category rows
categoriesContainer.removeAllViews();
for (String category : CATEGORIES) {
List<Restaurant> catList = new ArrayList<>();
for (Restaurant r : filteredRestaurants) {
if (category.equals(r.getCategory())) {
catList.add(r);
}
}
if (!catList.isEmpty()) {
View rowView = android.view.LayoutInflater.from(this).inflate(R.layout.item_category_row, categoriesContainer, false);
TextView txtTitle = rowView.findViewById(R.id.txtCategoryTitle);
RecyclerView rvCategory = rowView.findViewById(R.id.rvCategoryRestaurants);
txtTitle.setText(category);
rvCategory.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false));
rvCategory.setAdapter(new FeaturedRestaurantAdapter(catList, clickListener));
categoriesContainer.addView(rowView);
}
}
}
private String normalizeString(String str) {

View File

@@ -160,12 +160,19 @@ public class MainActivity extends AppCompatActivity {
permissionsNeeded.add(Manifest.permission.READ_EXTERNAL_STORAGE);
}
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
permissionsNeeded.add(Manifest.permission.POST_NOTIFICATIONS);
}
}
if (!permissionsNeeded.isEmpty()) {
new AlertDialog.Builder(this)
.setTitle("Permissões Necessárias")
.setMessage(
"Para o correto funcionamento do check-in, serviços de proximidade e fotos da galeria, precisamos de algumas permissões.")
"Para o correto funcionamento do check-in, receber notificações de reservas e acesso a fotos, precisamos de algumas permissões.")
.setPositiveButton("Configurar", (dialog, which) -> {
permissionRequest.launch(permissionsNeeded.toArray(new String[0]));
})

View File

@@ -112,24 +112,6 @@
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
<!-- Category Pills -->
<HorizontalScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:scrollbars="none"
android:clipToPadding="false"
android:paddingHorizontal="20dp">
<com.google.android.material.chip.ChipGroup
android:id="@+id/chipGroupCategories"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:singleLine="true"
app:singleSelection="true">
<!-- Chips will be added programmatically -->
</com.google.android.material.chip.ChipGroup>
</HorizontalScrollView>
<!-- Loading Spinner -->
<ProgressBar
@@ -173,36 +155,14 @@
tools:listitem="@layout/item_restaurant_featured" />
</LinearLayout>
<!-- Main Restaurant Grid/List -->
<!-- Dynamic Categories Container -->
<LinearLayout
android:id="@+id/layoutAllRestaurants"
android:id="@+id/categoriesContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:visibility="gone"
android:layout_marginTop="32dp">
<TextView
android:id="@+id/txtListTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:text="Todos os Restaurantes"
android:textColor="@color/colorTextPrimary"
android:textSize="20sp"
android:textStyle="bold"
android:fontFamily="sans-serif" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rvMainRestaurants"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:clipToPadding="false"
android:paddingBottom="16dp"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="@layout/item_restaurant" />
</LinearLayout>
android:layout_marginTop="8dp"
android:paddingBottom="16dp" />
</LinearLayout>
</ScrollView>

View File

@@ -14,7 +14,28 @@
<!-- Typography base generic configuration -->
<item name="android:fontFamily">sans-serif</item>
<!-- Modern Shape Appearance (Rounded Corners) -->
<item name="shapeAppearanceSmallComponent">@style/ShapeAppearance.App.SmallComponent</item>
<item name="shapeAppearanceMediumComponent">@style/ShapeAppearance.App.MediumComponent</item>
<item name="shapeAppearanceLargeComponent">@style/ShapeAppearance.App.LargeComponent</item>
</style>
<style name="Theme.Pap_teste" parent="Base.Theme.Pap_teste" />
<!-- Shape Styles -->
<style name="ShapeAppearance.App.SmallComponent" parent="ShapeAppearance.Material3.SmallComponent">
<item name="cornerFamily">rounded</item>
<item name="cornerSize">12dp</item>
</style>
<style name="ShapeAppearance.App.MediumComponent" parent="ShapeAppearance.Material3.MediumComponent">
<item name="cornerFamily">rounded</item>
<item name="cornerSize">16dp</item>
</style>
<style name="ShapeAppearance.App.LargeComponent" parent="ShapeAppearance.Material3.LargeComponent">
<item name="cornerFamily">rounded</item>
<item name="cornerSize">24dp</item>
</style>
</resources>