diff --git a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/AdoptionDetailFragment.java b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/AdoptionDetailFragment.java index d9d84fd6..61bed9f7 100644 --- a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/AdoptionDetailFragment.java +++ b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/AdoptionDetailFragment.java @@ -6,14 +6,13 @@ import android.util.Log; import android.view.*; import android.widget.*; import androidx.annotation.NonNull; -import androidx.appcompat.app.AlertDialog; import androidx.fragment.app.Fragment; import androidx.navigation.fragment.NavHostFragment; import com.example.petstoremobile.R; -import com.example.petstoremobile.adapters.BlackTextArrayAdapter; import com.example.petstoremobile.api.*; import com.example.petstoremobile.dtos.*; +import com.example.petstoremobile.utils.DialogUtils; import com.example.petstoremobile.utils.ErrorUtils; import com.example.petstoremobile.utils.SpinnerUtils; @@ -84,8 +83,7 @@ public class AdoptionDetailFragment extends Fragment { * Configures the spinner for adoption status. */ private void setupSpinners() { - spinnerStatus.setAdapter(new BlackTextArrayAdapter<>(requireContext(), - android.R.layout.simple_spinner_item, STATUSES)); + SpinnerUtils.setupStringSpinner(requireContext(), spinnerStatus, STATUSES); } /** @@ -172,12 +170,7 @@ public class AdoptionDetailFragment extends Fragment { btnDelete.setVisibility(View.VISIBLE); // Pre-fill status - String status = a.getString("adoptionStatus", "Pending"); - for (int i = 0; i < STATUSES.length; i++) { - if (STATUSES[i].equals(status)) { - spinnerStatus.setSelection(i); break; - } - } + SpinnerUtils.setSelectionByValue(spinnerStatus, a.getString("adoptionStatus", "Pending")); } else { tvMode.setText("Add Adoption"); btnDelete.setVisibility(View.GONE); @@ -247,18 +240,15 @@ public class AdoptionDetailFragment extends Fragment { * Shows a confirmation dialog before deleting an adoption request. */ private void confirmDelete() { - new AlertDialog.Builder(requireContext()) - .setTitle("Delete Adoption?") - .setPositiveButton("Yes", (d, w) -> - adoptionApi.deleteAdoption(adoptionId) - .enqueue(new Callback() { - public void onResponse(Call c, Response r) { navigateBack(); } - public void onFailure(Call c, Throwable t) { - Toast.makeText(getContext(), "Delete failed", - Toast.LENGTH_SHORT).show(); - } - })) - .setNegativeButton("No", null).show(); + DialogUtils.showDeleteConfirmDialog(requireContext(), "Adoption", () -> + adoptionApi.deleteAdoption(adoptionId) + .enqueue(new Callback() { + public void onResponse(Call c, Response r) { navigateBack(); } + public void onFailure(Call c, Throwable t) { + Toast.makeText(getContext(), "Delete failed", + Toast.LENGTH_SHORT).show(); + } + })); } /** diff --git a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/AppointmentDetailFragment.java b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/AppointmentDetailFragment.java index e1af3531..4f933788 100644 --- a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/AppointmentDetailFragment.java +++ b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/AppointmentDetailFragment.java @@ -6,14 +6,13 @@ import android.util.Log; import android.view.*; import android.widget.*; import androidx.annotation.NonNull; -import androidx.appcompat.app.AlertDialog; import androidx.fragment.app.Fragment; import androidx.navigation.fragment.NavHostFragment; import com.example.petstoremobile.R; -import com.example.petstoremobile.adapters.BlackTextArrayAdapter; import com.example.petstoremobile.api.*; import com.example.petstoremobile.dtos.*; +import com.example.petstoremobile.utils.DialogUtils; import com.example.petstoremobile.utils.ErrorUtils; import com.example.petstoremobile.utils.SpinnerUtils; @@ -317,7 +316,7 @@ public class AppointmentDetailFragment extends Fragment { 0 ); if (selected.before(Calendar.getInstance())) { - showErrorDialog("Invalid Time", + DialogUtils.showInfoDialog(requireContext(), "Invalid Time", "Booked appointments must be in the future. " + "Please select a future date and time."); return; @@ -368,7 +367,7 @@ public class AppointmentDetailFragment extends Fragment { // Show proper dialog based on error type if (errorBody.toLowerCase().contains("future")) { - showErrorDialog("Invalid Date/Time", + DialogUtils.showInfoDialog(requireContext(), "Invalid Date/Time", "Booked appointments must be scheduled in the future. " + "Please select a future date and time."); } else if (errorBody.toLowerCase().contains("not available") || @@ -379,7 +378,7 @@ public class AppointmentDetailFragment extends Fragment { } } catch (Exception e) { Log.e("APPT_SAVE", "Failed to read error body"); - showErrorDialog("Error", "Something went wrong. Please try again."); + DialogUtils.showInfoDialog(requireContext(), "Error", "Something went wrong. Please try again."); } } } @@ -395,7 +394,7 @@ public class AppointmentDetailFragment extends Fragment { * Shows a specialized dialog when a time slot is not available. */ private void showNoAvailabilityDialog() { - new AlertDialog.Builder(requireContext()) + new androidx.appcompat.app.AlertDialog.Builder(requireContext()) .setTitle("No Availability") .setMessage("This time slot is already booked for the selected service and store. Please choose a different time or date.") .setPositiveButton("Change Time", (d, w) -> d.dismiss()) @@ -404,32 +403,18 @@ public class AppointmentDetailFragment extends Fragment { .show(); } - /** - * Shows a generic error dialog with a title and message. - */ - private void showErrorDialog(String title, String message) { - new AlertDialog.Builder(requireContext()) - .setTitle(title) - .setMessage(message) - .setPositiveButton("OK", null) - .show(); - } - /** * Shows a confirmation dialog and handles the deletion of an appointment. */ private void confirmDelete() { - new AlertDialog.Builder(requireContext()) - .setTitle("Delete Appointment?") - .setPositiveButton("Yes", (d, w) -> - appointmentApi.deleteAppointment(appointmentId) - .enqueue(new Callback() { - public void onResponse(Call c, Response r) { navigateBack(); } - public void onFailure(Call c, Throwable t) { - Toast.makeText(getContext(), "Delete failed", Toast.LENGTH_SHORT).show(); - } - })) - .setNegativeButton("No", null).show(); + DialogUtils.showDeleteConfirmDialog(requireContext(), "Appointment", () -> + appointmentApi.deleteAppointment(appointmentId) + .enqueue(new Callback() { + public void onResponse(Call c, Response r) { navigateBack(); } + public void onFailure(Call c, Throwable t) { + Toast.makeText(getContext(), "Delete failed", Toast.LENGTH_SHORT).show(); + } + })); } /** diff --git a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/PetDetailFragment.java b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/PetDetailFragment.java index d4add362..78d5efb7 100644 --- a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/PetDetailFragment.java +++ b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/PetDetailFragment.java @@ -3,7 +3,6 @@ package com.example.petstoremobile.fragments.listfragments.detailfragments; import android.os.Bundle; import androidx.annotation.NonNull; -import androidx.appcompat.app.AlertDialog; import androidx.fragment.app.Fragment; import androidx.navigation.fragment.NavHostFragment; @@ -21,6 +20,7 @@ import com.example.petstoremobile.R; import com.example.petstoremobile.api.PetApi; import com.example.petstoremobile.dtos.PetDTO; import com.example.petstoremobile.utils.ActivityLogger; +import com.example.petstoremobile.utils.DialogUtils; import com.example.petstoremobile.utils.ErrorUtils; import com.example.petstoremobile.utils.InputValidator; import com.example.petstoremobile.utils.SpinnerUtils; @@ -144,34 +144,26 @@ public class PetDetailFragment extends Fragment { * Displays a confirmation dialog and handles the deletion of a pet. */ private void deletePet() { - //Alert the user to confirm the delete - new AlertDialog.Builder(requireContext()) - .setTitle("Delete Pet") - .setMessage("Are you sure you want to delete " + etPetName.getText().toString() + "?") - .setPositiveButton("Delete", (dialog, which) -> { - //if they say yes then delete the pet - petApi.deletePet((long) petId).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful()) { - ActivityLogger.logChange(requireContext(), "Pet", "DELETED", petId); - Toast.makeText(getContext(), "Pet deleted successfully!", Toast.LENGTH_SHORT).show(); - navigateBack(); - } else { - ErrorUtils.showErrorMessage(getContext(), response, "Failed to delete pet"); - } + DialogUtils.showDeleteConfirmDialog(requireContext(), "Pet", () -> + petApi.deletePet((long) petId).enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + if (response.isSuccessful()) { + ActivityLogger.logChange(requireContext(), "Pet", "DELETED", petId); + Toast.makeText(getContext(), "Pet deleted successfully!", Toast.LENGTH_SHORT).show(); + navigateBack(); + } else { + ErrorUtils.showErrorMessage(getContext(), response, "Failed to delete pet"); } + } - @Override - public void onFailure(Call call, Throwable t) { - ActivityLogger.logException(requireContext(), "PetDetailFragment.deletePet", new Exception(t)); - Log.e("PetDetailFragment", "Error deleting pet", t); - Toast.makeText(getContext(), "Network error: " + t.getMessage(), Toast.LENGTH_SHORT).show(); - } - }); - }) - .setNegativeButton("Cancel", null) - .show(); + @Override + public void onFailure(Call call, Throwable t) { + ActivityLogger.logException(requireContext(), "PetDetailFragment.deletePet", new Exception(t)); + Log.e("PetDetailFragment", "Error deleting pet", t); + Toast.makeText(getContext(), "Network error: " + t.getMessage(), Toast.LENGTH_SHORT).show(); + } + })); } /** diff --git a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/ProductDetailFragment.java b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/ProductDetailFragment.java index ae265b86..64f2c7f4 100644 --- a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/ProductDetailFragment.java +++ b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/ProductDetailFragment.java @@ -11,11 +11,11 @@ import androidx.navigation.fragment.NavHostFragment; import com.bumptech.glide.Glide; import com.example.petstoremobile.R; -import com.example.petstoremobile.adapters.BlackTextArrayAdapter; import com.example.petstoremobile.api.*; import com.example.petstoremobile.api.auth.TokenManager; import com.example.petstoremobile.dtos.*; import com.example.petstoremobile.viewmodels.ProductViewModel; +import com.example.petstoremobile.utils.DialogUtils; import com.example.petstoremobile.utils.ErrorUtils; import com.example.petstoremobile.utils.FileUtils; import com.example.petstoremobile.utils.GlideUtils; @@ -286,17 +286,14 @@ public class ProductDetailFragment extends Fragment { * Displays a confirmation dialog before deleting the product. */ private void confirmDelete() { - new androidx.appcompat.app.AlertDialog.Builder(requireContext()) - .setTitle("Delete Product?") - .setPositiveButton("Yes", (d, w) -> - viewModel.deleteProduct(prodId).observe(getViewLifecycleOwner(), resource -> { - if (resource != null && resource.status == com.example.petstoremobile.utils.Resource.Status.SUCCESS) { - navigateBack(); - } else if (resource != null && resource.status == com.example.petstoremobile.utils.Resource.Status.ERROR) { - Toast.makeText(getContext(), "Delete failed: " + resource.message, Toast.LENGTH_SHORT).show(); - } - })) - .setNegativeButton("No", null).show(); + DialogUtils.showDeleteConfirmDialog(requireContext(), "Product", () -> + viewModel.deleteProduct(prodId).observe(getViewLifecycleOwner(), resource -> { + if (resource != null && resource.status == com.example.petstoremobile.utils.Resource.Status.SUCCESS) { + navigateBack(); + } else if (resource != null && resource.status == com.example.petstoremobile.utils.Resource.Status.ERROR) { + Toast.makeText(getContext(), "Delete failed: " + resource.message, Toast.LENGTH_SHORT).show(); + } + })); } /** diff --git a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/ProductSupplierDetailFragment.java b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/ProductSupplierDetailFragment.java index 3c6ce82b..3db78dd0 100644 --- a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/ProductSupplierDetailFragment.java +++ b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/ProductSupplierDetailFragment.java @@ -5,14 +5,13 @@ import android.util.Log; import android.view.*; import android.widget.*; import androidx.annotation.NonNull; -import androidx.appcompat.app.AlertDialog; import androidx.fragment.app.Fragment; import androidx.navigation.fragment.NavHostFragment; import com.example.petstoremobile.R; -import com.example.petstoremobile.adapters.BlackTextArrayAdapter; import com.example.petstoremobile.api.*; import com.example.petstoremobile.dtos.*; +import com.example.petstoremobile.utils.DialogUtils; import com.example.petstoremobile.utils.ErrorUtils; import com.example.petstoremobile.utils.InputValidator; import com.example.petstoremobile.utils.SpinnerUtils; @@ -201,20 +200,17 @@ public class ProductSupplierDetailFragment extends Fragment { * Shows a confirmation dialog before deleting a product-supplier relationship. */ private void confirmDelete() { - new AlertDialog.Builder(requireContext()) - .setTitle("Delete?") - .setPositiveButton("Yes", (d, w) -> - productSupplierApi.deleteProductSupplier(editProductId, editSupplierId) - .enqueue(new Callback() { - public void onResponse(Call c, Response r) { - navigateBack(); - } - public void onFailure(Call c, Throwable t) { - Toast.makeText(getContext(), "Delete failed", - Toast.LENGTH_SHORT).show(); - } - })) - .setNegativeButton("No", null).show(); + DialogUtils.showDeleteConfirmDialog(requireContext(), "Product Supplier", () -> + productSupplierApi.deleteProductSupplier(editProductId, editSupplierId) + .enqueue(new Callback() { + public void onResponse(Call c, Response r) { + navigateBack(); + } + public void onFailure(Call c, Throwable t) { + Toast.makeText(getContext(), "Delete failed", + Toast.LENGTH_SHORT).show(); + } + })); } /** diff --git a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/ServiceDetailFragment.java b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/ServiceDetailFragment.java index 577211bf..a70cb266 100644 --- a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/ServiceDetailFragment.java +++ b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/ServiceDetailFragment.java @@ -2,7 +2,6 @@ package com.example.petstoremobile.fragments.listfragments.detailfragments; import android.os.Bundle; -import androidx.appcompat.app.AlertDialog; import androidx.fragment.app.Fragment; import androidx.navigation.fragment.NavHostFragment; @@ -19,6 +18,7 @@ import com.example.petstoremobile.R; import com.example.petstoremobile.api.ServiceApi; import com.example.petstoremobile.dtos.ServiceDTO; import com.example.petstoremobile.utils.ActivityLogger; +import com.example.petstoremobile.utils.DialogUtils; import com.example.petstoremobile.utils.ErrorUtils; import com.example.petstoremobile.utils.InputValidator; @@ -134,33 +134,26 @@ public class ServiceDetailFragment extends Fragment { * Displays a confirmation dialog and handles the deletion of a service. */ private void deleteService() { - //Alert the user to confirm the delete - new AlertDialog.Builder(requireContext()) - .setTitle("Delete Service") - .setMessage("Are you sure you want to delete " + etServiceName.getText().toString() + "?") - .setPositiveButton("Delete", (dialog, which) -> { - serviceApi.deleteService((long) serviceId).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful()) { - ActivityLogger.logChange(requireContext(), "Service", "DELETED", serviceId); - Toast.makeText(getContext(), "Service deleted successfully!", Toast.LENGTH_SHORT).show(); - navigateBack(); - } else { - ErrorUtils.showErrorMessage(getContext(), response, "Failed to delete service"); - } + DialogUtils.showDeleteConfirmDialog(requireContext(), "Service", () -> + serviceApi.deleteService((long) serviceId).enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + if (response.isSuccessful()) { + ActivityLogger.logChange(requireContext(), "Service", "DELETED", serviceId); + Toast.makeText(getContext(), "Service deleted successfully!", Toast.LENGTH_SHORT).show(); + navigateBack(); + } else { + ErrorUtils.showErrorMessage(getContext(), response, "Failed to delete service"); } + } - @Override - public void onFailure(Call call, Throwable t) { - ActivityLogger.logException(requireContext(), "ServiceDetailFragment.deleteService", new Exception(t)); - Log.e("ServiceDetailFragment", "Error deleting service", t); - Toast.makeText(getContext(), "Network error: " + t.getMessage(), Toast.LENGTH_SHORT).show(); - } - }); - }) - .setNegativeButton("Cancel", null) - .show(); + @Override + public void onFailure(Call call, Throwable t) { + ActivityLogger.logException(requireContext(), "ServiceDetailFragment.deleteService", new Exception(t)); + Log.e("ServiceDetailFragment", "Error deleting service", t); + Toast.makeText(getContext(), "Network error: " + t.getMessage(), Toast.LENGTH_SHORT).show(); + } + })); } /** diff --git a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/SupplierDetailFragment.java b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/SupplierDetailFragment.java index e4b41598..3001faad 100644 --- a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/SupplierDetailFragment.java +++ b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/SupplierDetailFragment.java @@ -2,7 +2,6 @@ package com.example.petstoremobile.fragments.listfragments.detailfragments; import android.os.Bundle; -import androidx.appcompat.app.AlertDialog; import androidx.fragment.app.Fragment; import androidx.navigation.fragment.NavHostFragment; @@ -19,6 +18,7 @@ import com.example.petstoremobile.R; import com.example.petstoremobile.api.SupplierApi; import com.example.petstoremobile.dtos.SupplierDTO; import com.example.petstoremobile.utils.ActivityLogger; +import com.example.petstoremobile.utils.DialogUtils; import com.example.petstoremobile.utils.ErrorUtils; import com.example.petstoremobile.utils.InputValidator; import com.example.petstoremobile.utils.UIUtils; @@ -138,33 +138,26 @@ public class SupplierDetailFragment extends Fragment { * Displays a confirmation dialog and handles the deletion of a supplier. */ private void deleteSupplier() { - //Alert the user to confirm the delete - new AlertDialog.Builder(requireContext()) - .setTitle("Delete Supplier") - .setMessage("Are you sure you want to delete " + etSupCompany.getText().toString() + "?") - .setPositiveButton("Delete", (dialog, which) -> { - supplierApi.deleteSupplier((long) supId).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful()) { - ActivityLogger.logChange(requireContext(), "Supplier", "DELETED", supId); - Toast.makeText(getContext(), "Supplier deleted successfully!", Toast.LENGTH_SHORT).show(); - navigateBack(); - } else { - ErrorUtils.showErrorMessage(getContext(), response, "Failed to delete supplier"); - } + DialogUtils.showDeleteConfirmDialog(requireContext(), "Supplier", () -> + supplierApi.deleteSupplier((long) supId).enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + if (response.isSuccessful()) { + ActivityLogger.logChange(requireContext(), "Supplier", "DELETED", supId); + Toast.makeText(getContext(), "Supplier deleted successfully!", Toast.LENGTH_SHORT).show(); + navigateBack(); + } else { + ErrorUtils.showErrorMessage(getContext(), response, "Failed to delete supplier"); } + } - @Override - public void onFailure(Call call, Throwable t) { - ActivityLogger.logException(requireContext(), "SupplierDetailFragment.deleteSupplier", new Exception(t)); - Log.e("SupplierDetailFragment", "Error deleting supplier", t); - Toast.makeText(getContext(), "Network error: " + t.getMessage(), Toast.LENGTH_SHORT).show(); - } - }); - }) - .setNegativeButton("Cancel", null) - .show(); + @Override + public void onFailure(Call call, Throwable t) { + ActivityLogger.logException(requireContext(), "SupplierDetailFragment.deleteSupplier", new Exception(t)); + Log.e("SupplierDetailFragment", "Error deleting supplier", t); + Toast.makeText(getContext(), "Network error: " + t.getMessage(), Toast.LENGTH_SHORT).show(); + } + })); } /** diff --git a/android/app/src/main/java/com/example/petstoremobile/utils/DialogUtils.java b/android/app/src/main/java/com/example/petstoremobile/utils/DialogUtils.java new file mode 100644 index 00000000..55436846 --- /dev/null +++ b/android/app/src/main/java/com/example/petstoremobile/utils/DialogUtils.java @@ -0,0 +1,47 @@ +package com.example.petstoremobile.utils; + +import android.content.Context; +import androidx.appcompat.app.AlertDialog; + +/** + * Utility class for creating and displaying common dialogs. + */ +public class DialogUtils { + + /** + * Interface for handling dialog button clicks. + */ + public interface DialogCallback { + void onConfirm(); + } + + /** + * Shows a confirmation dialog with "Yes" and "No" buttons. + */ + public static void showConfirmDialog(Context context, String title, String message, DialogCallback callback) { + new AlertDialog.Builder(context) + .setTitle(title) + .setMessage(message) + .setPositiveButton("Yes", (dialog, which) -> callback.onConfirm()) + .setNegativeButton("No", null) + .show(); + } + + /** + * Shows a delete confirmation dialog. + */ + public static void showDeleteConfirmDialog(Context context, String itemName, DialogCallback callback) { + showConfirmDialog(context, "Delete " + itemName + "?", "Are you sure you want to delete this " + itemName.toLowerCase() + "? This action cannot be undone.", callback); + } + + /** + * Shows a simple information or error dialog with an "OK" button. + */ + public static void showInfoDialog(Context context, String title, String message) { + new AlertDialog.Builder(context) + .setTitle(title) + .setMessage(message) + .setPositiveButton("OK", null) + .show(); + } +}