9/06
This commit is contained in:
@@ -14,6 +14,10 @@
|
|||||||
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" />
|
<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_SCAN" />
|
||||||
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
|
<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
|
<application
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
@@ -113,6 +117,11 @@
|
|||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
|
<service
|
||||||
|
android:name=".ReservationNotificationService"
|
||||||
|
android:exported="false"
|
||||||
|
android:foregroundServiceType="dataSync" />
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
@@ -37,19 +37,17 @@ public class ClientDashboardActivity extends AppCompatActivity {
|
|||||||
private TextView txtGreeting;
|
private TextView txtGreeting;
|
||||||
private ImageView imgProfile;
|
private ImageView imgProfile;
|
||||||
private EditText etSearch;
|
private EditText etSearch;
|
||||||
private ChipGroup chipGroupCategories;
|
private RecyclerView rvFeatured;
|
||||||
private RecyclerView rvFeatured, rvMainRestaurants;
|
|
||||||
private ProgressBar progressBar;
|
private ProgressBar progressBar;
|
||||||
private View layoutFeatured, layoutAllRestaurants;
|
private View layoutFeatured;
|
||||||
|
private android.widget.LinearLayout categoriesContainer;
|
||||||
|
|
||||||
private List<Restaurant> allRestaurants = new ArrayList<>();
|
private List<Restaurant> allRestaurants = new ArrayList<>();
|
||||||
private List<Restaurant> filteredRestaurants = new ArrayList<>();
|
private List<Restaurant> filteredRestaurants = new ArrayList<>();
|
||||||
|
|
||||||
private RestaurantAdapter mainAdapter;
|
|
||||||
private FeaturedRestaurantAdapter featuredAdapter;
|
private FeaturedRestaurantAdapter featuredAdapter;
|
||||||
|
|
||||||
private final String[] CATEGORIES = { "Tudo", "Carnes", "Massas", "Sushi", "Pizzas", "Sobremesas" };
|
private final String[] CATEGORIES = { "Carnes", "Massas", "Sushi", "Pizzas", "Sobremesas" };
|
||||||
private String currentCategoryFilter = "Tudo";
|
|
||||||
private String currentSearchFilter = "";
|
private String currentSearchFilter = "";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -70,43 +68,38 @@ public class ClientDashboardActivity extends AppCompatActivity {
|
|||||||
initViews();
|
initViews();
|
||||||
setupBottomNavigation();
|
setupBottomNavigation();
|
||||||
setupSearch();
|
setupSearch();
|
||||||
setupCategories();
|
|
||||||
|
|
||||||
updateGreeting();
|
updateGreeting();
|
||||||
fetchProfilePicture();
|
fetchProfilePicture();
|
||||||
fetchRestaurants();
|
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() {
|
private void initViews() {
|
||||||
txtGreeting = findViewById(R.id.txtClientGreeting);
|
txtGreeting = findViewById(R.id.txtClientGreeting);
|
||||||
imgProfile = findViewById(R.id.imgProfile);
|
imgProfile = findViewById(R.id.imgProfile);
|
||||||
etSearch = findViewById(R.id.etSearch);
|
etSearch = findViewById(R.id.etSearch);
|
||||||
chipGroupCategories = findViewById(R.id.chipGroupCategories);
|
|
||||||
rvFeatured = findViewById(R.id.rvFeatured);
|
rvFeatured = findViewById(R.id.rvFeatured);
|
||||||
rvMainRestaurants = findViewById(R.id.rvMainRestaurants);
|
|
||||||
progressBar = findViewById(R.id.progressBar);
|
progressBar = findViewById(R.id.progressBar);
|
||||||
layoutFeatured = findViewById(R.id.layoutFeatured);
|
layoutFeatured = findViewById(R.id.layoutFeatured);
|
||||||
layoutAllRestaurants = findViewById(R.id.layoutAllRestaurants);
|
categoriesContainer = findViewById(R.id.categoriesContainer);
|
||||||
|
|
||||||
rvFeatured.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false));
|
rvFeatured.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false));
|
||||||
rvMainRestaurants.setLayoutManager(new LinearLayoutManager(this));
|
|
||||||
|
|
||||||
// Click listener for restaurants to open booking flow
|
// Click listener for restaurants to open booking flow
|
||||||
RestaurantAdapter.OnRestaurantClickListener clickListener = restaurant -> {
|
clickListener = restaurant -> {
|
||||||
Intent intent = new Intent(this, ExplorarRestaurantesActivity.class);
|
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);
|
intent.putExtra("restaurant", restaurant);
|
||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
};
|
};
|
||||||
|
|
||||||
featuredAdapter = new FeaturedRestaurantAdapter(new ArrayList<>(), clickListener);
|
featuredAdapter = new FeaturedRestaurantAdapter(new ArrayList<>(), clickListener);
|
||||||
mainAdapter = new RestaurantAdapter(filteredRestaurants, clickListener);
|
|
||||||
|
|
||||||
rvFeatured.setAdapter(featuredAdapter);
|
rvFeatured.setAdapter(featuredAdapter);
|
||||||
rvMainRestaurants.setAdapter(mainAdapter);
|
|
||||||
|
|
||||||
// Click listener for profile picture in the header
|
// Click listener for profile picture in the header
|
||||||
findViewById(R.id.cardProfile).setOnClickListener(v -> {
|
findViewById(R.id.cardProfile).setOnClickListener(v -> {
|
||||||
@@ -163,7 +156,7 @@ public class ClientDashboardActivity extends AppCompatActivity {
|
|||||||
private void fetchRestaurants() {
|
private void fetchRestaurants() {
|
||||||
progressBar.setVisibility(View.VISIBLE);
|
progressBar.setVisibility(View.VISIBLE);
|
||||||
layoutFeatured.setVisibility(View.GONE);
|
layoutFeatured.setVisibility(View.GONE);
|
||||||
layoutAllRestaurants.setVisibility(View.GONE);
|
categoriesContainer.removeAllViews();
|
||||||
|
|
||||||
DatabaseReference usersRef = FirebaseDatabase.getInstance().getReference("Restaurantes");
|
DatabaseReference usersRef = FirebaseDatabase.getInstance().getReference("Restaurantes");
|
||||||
usersRef.addValueEventListener(new ValueEventListener() {
|
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() {
|
private void setupSearch() {
|
||||||
etSearch.addTextChangedListener(new TextWatcher() {
|
etSearch.addTextChangedListener(new TextWatcher() {
|
||||||
@Override
|
@Override
|
||||||
@@ -271,35 +223,46 @@ public class ClientDashboardActivity extends AppCompatActivity {
|
|||||||
String normalizedSearch = normalizeString(currentSearchFilter);
|
String normalizedSearch = normalizeString(currentSearchFilter);
|
||||||
|
|
||||||
for (Restaurant r : allRestaurants) {
|
for (Restaurant r : allRestaurants) {
|
||||||
boolean matchesCategory = currentCategoryFilter.equals("Tudo")
|
|
||||||
|| currentCategoryFilter.equals(r.getCategory());
|
|
||||||
|
|
||||||
String normalizedName = normalizeString(r.getName());
|
String normalizedName = normalizeString(r.getName());
|
||||||
boolean matchesSearch = currentSearchFilter.isEmpty() || normalizedName.contains(normalizedSearch);
|
boolean matchesSearch = currentSearchFilter.isEmpty() || normalizedName.contains(normalizedSearch);
|
||||||
|
|
||||||
if (matchesCategory && matchesSearch) {
|
if (matchesSearch) {
|
||||||
filteredRestaurants.add(r);
|
filteredRestaurants.add(r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mainAdapter.notifyDataSetChanged();
|
// Update featured carousel with top restaurants
|
||||||
|
|
||||||
// Update featured (just the first 3 for demo, or based on a specific logic)
|
|
||||||
List<Restaurant> featuredList = new ArrayList<>();
|
List<Restaurant> featuredList = new ArrayList<>();
|
||||||
for (int i = 0; i < Math.min(3, filteredRestaurants.size()); i++) {
|
for (int i = 0; i < Math.min(3, filteredRestaurants.size()); i++) {
|
||||||
featuredList.add(filteredRestaurants.get(i));
|
featuredList.add(filteredRestaurants.get(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
featuredAdapter = new FeaturedRestaurantAdapter(featuredList,
|
featuredAdapter = new FeaturedRestaurantAdapter(featuredList, clickListener);
|
||||||
mainAdapter instanceof RestaurantAdapter ? restaurant -> {
|
|
||||||
Intent intent = new Intent(this, ExplorarRestaurantesActivity.class);
|
|
||||||
intent.putExtra("restaurant", restaurant);
|
|
||||||
startActivity(intent);
|
|
||||||
} : null);
|
|
||||||
rvFeatured.setAdapter(featuredAdapter);
|
rvFeatured.setAdapter(featuredAdapter);
|
||||||
|
|
||||||
layoutFeatured.setVisibility(featuredList.isEmpty() ? View.GONE : View.VISIBLE);
|
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) {
|
private String normalizeString(String str) {
|
||||||
|
|||||||
@@ -160,12 +160,19 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
permissionsNeeded.add(Manifest.permission.READ_EXTERNAL_STORAGE);
|
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()) {
|
if (!permissionsNeeded.isEmpty()) {
|
||||||
new AlertDialog.Builder(this)
|
new AlertDialog.Builder(this)
|
||||||
.setTitle("Permissões Necessárias")
|
.setTitle("Permissões Necessárias")
|
||||||
.setMessage(
|
.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) -> {
|
.setPositiveButton("Configurar", (dialog, which) -> {
|
||||||
permissionRequest.launch(permissionsNeeded.toArray(new String[0]));
|
permissionRequest.launch(permissionsNeeded.toArray(new String[0]));
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -112,24 +112,6 @@
|
|||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</com.google.android.material.card.MaterialCardView>
|
</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 -->
|
<!-- Loading Spinner -->
|
||||||
<ProgressBar
|
<ProgressBar
|
||||||
@@ -173,36 +155,14 @@
|
|||||||
tools:listitem="@layout/item_restaurant_featured" />
|
tools:listitem="@layout/item_restaurant_featured" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<!-- Main Restaurant Grid/List -->
|
<!-- Dynamic Categories Container -->
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/layoutAllRestaurants"
|
android:id="@+id/categoriesContainer"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:visibility="gone"
|
android:layout_marginTop="8dp"
|
||||||
android:layout_marginTop="32dp">
|
android:paddingBottom="16dp" />
|
||||||
|
|
||||||
<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>
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
|||||||
@@ -14,7 +14,28 @@
|
|||||||
|
|
||||||
<!-- Typography base generic configuration -->
|
<!-- Typography base generic configuration -->
|
||||||
<item name="android:fontFamily">sans-serif</item>
|
<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>
|
||||||
|
|
||||||
<style name="Theme.Pap_teste" parent="Base.Theme.Pap_teste" />
|
<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>
|
</resources>
|
||||||
Reference in New Issue
Block a user