Created Spinner Helper class and removed reducdent code

This commit is contained in:
Alex
2026-04-05 18:15:36 -06:00
parent e354592c47
commit 6d990fbc63
8 changed files with 134 additions and 245 deletions

View File

@@ -15,6 +15,7 @@ import com.example.petstoremobile.adapters.BlackTextArrayAdapter;
import com.example.petstoremobile.api.*;
import com.example.petstoremobile.dtos.*;
import com.example.petstoremobile.utils.ErrorUtils;
import com.example.petstoremobile.utils.SpinnerUtils;
import java.util.*;
@@ -120,7 +121,9 @@ public class AdoptionDetailFragment extends Fragment {
Response<PageResponse<PetDTO>> r) {
if (r.isSuccessful() && r.body() != null) {
petList = r.body().getContent();
populatePetSpinner();
SpinnerUtils.populateSpinner(requireContext(), spinnerPet, petList,
PetDTO::getPetName, "-- Select Pet --",
preselectedPetId, PetDTO::getPetId);
}
}
public void onFailure(Call<PageResponse<PetDTO>> c, Throwable t) {
@@ -129,24 +132,6 @@ public class AdoptionDetailFragment extends Fragment {
});
}
/**
* Populates the pet selection spinner.
*/
private void populatePetSpinner() {
List<String> names = new ArrayList<>();
names.add("-- Select Pet --");
for (PetDTO p : petList) names.add(p.getPetName());
spinnerPet.setAdapter(new BlackTextArrayAdapter<>(requireContext(),
android.R.layout.simple_spinner_item, names));
if (preselectedPetId != -1) {
for (int i = 0; i < petList.size(); i++) {
if (petList.get(i).getPetId().equals(preselectedPetId)) {
spinnerPet.setSelection(i + 1); break;
}
}
}
}
/**
* Loads the list of customers from the API.
*/
@@ -157,7 +142,10 @@ public class AdoptionDetailFragment extends Fragment {
Response<PageResponse<CustomerDTO>> r) {
if (r.isSuccessful() && r.body() != null) {
customerList = r.body().getContent();
populateCustomerSpinner();
SpinnerUtils.populateSpinner(requireContext(), spinnerCustomer, customerList,
item -> item.getFirstName() + " " + item.getLastName(),
"-- Select Customer --",
preselectedCustomerId, CustomerDTO::getCustomerId);
}
}
public void onFailure(Call<PageResponse<CustomerDTO>> c, Throwable t) {
@@ -166,25 +154,6 @@ public class AdoptionDetailFragment extends Fragment {
});
}
/**
* Populates the customer selection spinner.
*/
private void populateCustomerSpinner() {
List<String> names = new ArrayList<>();
names.add("-- Select Customer --");
for (CustomerDTO c : customerList)
names.add(c.getFirstName() + " " + c.getLastName());
spinnerCustomer.setAdapter(new BlackTextArrayAdapter<>(requireContext(),
android.R.layout.simple_spinner_item, names));
if (preselectedCustomerId != -1) {
for (int i = 0; i < customerList.size(); i++) {
if (customerList.get(i).getCustomerId().equals(preselectedCustomerId)) {
spinnerCustomer.setSelection(i + 1); break;
}
}
}
}
/**
* Handles arguments to determine if the fragment is in edit or add mode.
*/

View File

@@ -15,6 +15,7 @@ import com.example.petstoremobile.adapters.BlackTextArrayAdapter;
import com.example.petstoremobile.api.*;
import com.example.petstoremobile.dtos.*;
import com.example.petstoremobile.utils.ErrorUtils;
import com.example.petstoremobile.utils.SpinnerUtils;
import java.util.*;
@@ -96,16 +97,13 @@ public class AppointmentDetailFragment extends Fragment {
* Configures the adapters for spinners.
*/
private void setupSpinners() {
spinnerStatus.setAdapter(new BlackTextArrayAdapter<>(requireContext(),
android.R.layout.simple_spinner_item, STATUSES));
SpinnerUtils.setupStringSpinner(requireContext(), spinnerStatus, STATUSES);
String[] hours = new String[HOURS.length];
for (int i = 0; i < HOURS.length; i++)
hours[i] = String.format("%02d:00", HOURS[i]);
spinnerHour.setAdapter(new BlackTextArrayAdapter<>(requireContext(),
android.R.layout.simple_spinner_item, hours));
spinnerMinute.setAdapter(new BlackTextArrayAdapter<>(requireContext(),
android.R.layout.simple_spinner_item, new String[]{"00","15","30","45"}));
SpinnerUtils.setupStringSpinner(requireContext(), spinnerHour, hours);
SpinnerUtils.setupStringSpinner(requireContext(), spinnerMinute, new String[]{"00","15","30","45"});
}
/**
@@ -144,7 +142,9 @@ public class AppointmentDetailFragment extends Fragment {
public void onResponse(Call<PageResponse<PetDTO>> c, Response<PageResponse<PetDTO>> r) {
if (r.isSuccessful() && r.body() != null) {
petList = r.body().getContent();
populatePetSpinner();
SpinnerUtils.populateSpinner(requireContext(), spinnerPet, petList,
PetDTO::getPetName, "-- Select Pet --",
preselectedPetId, PetDTO::getPetId);
}
}
public void onFailure(Call<PageResponse<PetDTO>> c, Throwable t) {
@@ -153,24 +153,6 @@ public class AppointmentDetailFragment extends Fragment {
});
}
/**
* Populates the pet selection spinner.
*/
private void populatePetSpinner() {
List<String> names = new ArrayList<>();
names.add("-- Select Pet --");
for (PetDTO p : petList) names.add(p.getPetName());
spinnerPet.setAdapter(new BlackTextArrayAdapter<>(requireContext(),
android.R.layout.simple_spinner_item, names));
if (preselectedPetId != -1) {
for (int i = 0; i < petList.size(); i++) {
if (petList.get(i).getPetId().equals(preselectedPetId)) {
spinnerPet.setSelection(i + 1); break;
}
}
}
}
/**
* Loads the list of services from the API.
*/
@@ -180,7 +162,9 @@ public class AppointmentDetailFragment extends Fragment {
public void onResponse(Call<PageResponse<ServiceDTO>> c, Response<PageResponse<ServiceDTO>> r) {
if (r.isSuccessful() && r.body() != null) {
serviceList = r.body().getContent();
populateServiceSpinner();
SpinnerUtils.populateSpinner(requireContext(), spinnerService, serviceList,
ServiceDTO::getServiceName, "-- Select Service --",
preselectedServiceId, ServiceDTO::getServiceId);
}
}
public void onFailure(Call<PageResponse<ServiceDTO>> c, Throwable t) {
@@ -189,24 +173,6 @@ public class AppointmentDetailFragment extends Fragment {
});
}
/**
* Populates the service selection spinner.
*/
private void populateServiceSpinner() {
List<String> names = new ArrayList<>();
names.add("-- Select Service --");
for (ServiceDTO s : serviceList) names.add(s.getServiceName());
spinnerService.setAdapter(new BlackTextArrayAdapter<>(requireContext(),
android.R.layout.simple_spinner_item, names));
if (preselectedServiceId != -1) {
for (int i = 0; i < serviceList.size(); i++) {
if (serviceList.get(i).getServiceId().equals(preselectedServiceId)) {
spinnerService.setSelection(i + 1); break;
}
}
}
}
/**
* Loads the list of customers from the API.
*/
@@ -216,7 +182,10 @@ public class AppointmentDetailFragment extends Fragment {
public void onResponse(Call<PageResponse<CustomerDTO>> c, Response<PageResponse<CustomerDTO>> r) {
if (r.isSuccessful() && r.body() != null) {
customerList = r.body().getContent();
populateCustomerSpinner();
SpinnerUtils.populateSpinner(requireContext(), spinnerCustomer, customerList,
item -> item.getFirstName() + " " + item.getLastName(),
"-- Select Customer --",
preselectedCustomerId, CustomerDTO::getCustomerId);
}
}
public void onFailure(Call<PageResponse<CustomerDTO>> c, Throwable t) {
@@ -225,25 +194,6 @@ public class AppointmentDetailFragment extends Fragment {
});
}
/**
* Populates the customer spinner.
*/
private void populateCustomerSpinner() {
List<String> names = new ArrayList<>();
names.add("-- Select Customer --");
for (CustomerDTO c : customerList)
names.add(c.getFirstName() + " " + c.getLastName());
spinnerCustomer.setAdapter(new BlackTextArrayAdapter<>(requireContext(),
android.R.layout.simple_spinner_item, names));
if (preselectedCustomerId != -1) {
for (int i = 0; i < customerList.size(); i++) {
if (customerList.get(i).getCustomerId().equals(preselectedCustomerId)) {
spinnerCustomer.setSelection(i + 1); break;
}
}
}
}
/**
* Loads the list of stores from the API.
*/
@@ -253,7 +203,9 @@ public class AppointmentDetailFragment extends Fragment {
public void onResponse(Call<PageResponse<StoreDTO>> c, Response<PageResponse<StoreDTO>> r) {
if (r.isSuccessful() && r.body() != null) {
storeList = r.body().getContent();
populateStoreSpinner();
SpinnerUtils.populateSpinner(requireContext(), spinnerStore, storeList,
StoreDTO::getStoreName, "-- Select Store --",
preselectedStoreId, StoreDTO::getStoreId);
}
}
public void onFailure(Call<PageResponse<StoreDTO>> c, Throwable t) {
@@ -262,24 +214,6 @@ public class AppointmentDetailFragment extends Fragment {
});
}
/**
* Populates the store spinner.
*/
private void populateStoreSpinner() {
List<String> names = new ArrayList<>();
names.add("-- Select Store --");
for (StoreDTO s : storeList) names.add(s.getStoreName());
spinnerStore.setAdapter(new BlackTextArrayAdapter<>(requireContext(),
android.R.layout.simple_spinner_item, names));
if (preselectedStoreId != -1) {
for (int i = 0; i < storeList.size(); i++) {
if (storeList.get(i).getStoreId().equals(preselectedStoreId)) {
spinnerStore.setSelection(i + 1); break;
}
}
}
}
/**
* Loads all appointments from the API.
*/
@@ -327,9 +261,7 @@ public class AppointmentDetailFragment extends Fragment {
}
// Pre-fill status
String status = a.getString("appointmentStatus", "Booked");
for (int i = 0; i < STATUSES.length; i++)
if (STATUSES[i].equals(status)) { spinnerStatus.setSelection(i); break; }
SpinnerUtils.setSelectionByValue(spinnerStatus, a.getString("appointmentStatus", "Booked"));
} else {
tvMode.setText("Add Appointment");

View File

@@ -27,6 +27,7 @@ import com.example.petstoremobile.dtos.InventoryRequest;
import com.example.petstoremobile.dtos.PageResponse;
import com.example.petstoremobile.dtos.ProductDTO;
import com.example.petstoremobile.utils.ErrorUtils;
import com.example.petstoremobile.utils.InputValidator;
import java.util.ArrayList;
import java.util.List;
@@ -230,26 +231,12 @@ public class InventoryDetailFragment extends Fragment {
return;
}
String quantityStr = etQuantity.getText().toString().trim();
if (quantityStr.isEmpty()) {
etQuantity.setError("Quantity is required");
etQuantity.requestFocus();
if (!InputValidator.isNotEmpty(etQuantity, "Quantity") ||
!InputValidator.isPositiveInteger(etQuantity, "Quantity")) {
return;
}
int quantity;
try {
quantity = Integer.parseInt(quantityStr);
} catch (NumberFormatException e) {
etQuantity.setError("Invalid quantity");
return;
}
if (quantity < 0) {
etQuantity.setError("Quantity must be 0 or more");
etQuantity.requestFocus();
return;
}
int quantity = Integer.parseInt(etQuantity.getText().toString().trim());
InventoryRequest request = new InventoryRequest(selectedProduct.getProdId(), quantity);
setButtonsEnabled(false);

View File

@@ -18,12 +18,12 @@ import android.widget.TextView;
import android.widget.Toast;
import com.example.petstoremobile.R;
import com.example.petstoremobile.adapters.BlackTextArrayAdapter;
import com.example.petstoremobile.api.PetApi;
import com.example.petstoremobile.dtos.PetDTO;
import com.example.petstoremobile.utils.ActivityLogger;
import com.example.petstoremobile.utils.ErrorUtils;
import com.example.petstoremobile.utils.InputValidator;
import com.example.petstoremobile.utils.SpinnerUtils;
import javax.inject.Inject;
@@ -197,12 +197,9 @@ public class PetDetailFragment extends Fragment {
etPetBreed.setText(getArguments().getString("petBreed"));
etPetAge.setText(String.valueOf(getArguments().getInt("petAge")));
etPetPrice.setText(String.valueOf(getArguments().getDouble("petPrice")));
String status = getArguments().getString("petStatus");
if ("Available".equals(status)) {
spinnerPetStatus.setSelection(0);
} else {
spinnerPetStatus.setSelection(1);
}
SpinnerUtils.setSelectionByValue(spinnerPetStatus, getArguments().getString("petStatus"));
btnDeletePet.setVisibility(View.VISIBLE);
} else {
// Pet is being added
@@ -236,11 +233,8 @@ public class PetDetailFragment extends Fragment {
* Initializes the spinner for pet status selection.
*/
private void setupSpinner() {
BlackTextArrayAdapter<String> adapter = new BlackTextArrayAdapter<>(requireContext(),
android.R.layout.simple_spinner_item,
SpinnerUtils.setupStringSpinner(requireContext(), spinnerPetStatus,
new String[]{"Available", "Adopted"});
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinnerPetStatus.setAdapter(adapter);
}
}

View File

@@ -20,12 +20,15 @@ import com.example.petstoremobile.utils.ErrorUtils;
import com.example.petstoremobile.utils.FileUtils;
import com.example.petstoremobile.utils.GlideUtils;
import com.example.petstoremobile.utils.ImagePickerHelper;
import com.example.petstoremobile.utils.InputValidator;
import com.example.petstoremobile.utils.SpinnerUtils;
import java.io.File;
import java.math.BigDecimal;
import java.util.*;
import javax.inject.Inject;
import javax.inject.Named;
import dagger.hilt.android.AndroidEntryPoint;
@@ -130,29 +133,13 @@ public class ProductDetailFragment extends Fragment {
viewModel.getAllCategories(0, 100).observe(getViewLifecycleOwner(), resource -> {
if (resource != null && resource.status == com.example.petstoremobile.utils.Resource.Status.SUCCESS && resource.data != null) {
categoryList = resource.data.getContent();
populateCategorySpinner();
SpinnerUtils.populateSpinner(requireContext(), spinnerCategory, categoryList,
CategoryDTO::getCategoryName, "-- Select Category --",
preselectedCategoryId, CategoryDTO::getCategoryId);
}
});
}
/**
* Fills the spinner with category names.
*/
private void populateCategorySpinner() {
List<String> names = new ArrayList<>();
names.add("-- Select Category --");
for (CategoryDTO c : categoryList) names.add(c.getCategoryName());
spinnerCategory.setAdapter(new BlackTextArrayAdapter<>(requireContext(),
android.R.layout.simple_spinner_item, names));
if (preselectedCategoryId != -1) {
for (int i = 0; i < categoryList.size(); i++) {
if (categoryList.get(i).getCategoryId().equals(preselectedCategoryId)) {
spinnerCategory.setSelection(i + 1); break;
}
}
}
}
/**
* Checks if the fragment was opened with existing product data for editing.
*/
@@ -253,28 +240,22 @@ public class ProductDetailFragment extends Fragment {
* Validates input fields and saves product information to the backend.
*/
private void saveProduct() {
String name = etProductName.getText().toString().trim();
String desc = etProductDesc.getText().toString().trim();
String priceStr = etProductPrice.getText().toString().trim();
if (!InputValidator.isNotEmpty(etProductName, "Product Name")) return;
if (name.isEmpty()) {
etProductName.setError("Enter product name"); return;
}
if (spinnerCategory.getSelectedItemPosition() == 0) {
Toast.makeText(getContext(), "Select a category", Toast.LENGTH_SHORT).show(); return;
}
if (priceStr.isEmpty()) {
etProductPrice.setError("Enter price"); return;
if (!InputValidator.isNotEmpty(etProductPrice, "Price") ||
!InputValidator.isPositiveDecimal(etProductPrice, "Price")) {
return;
}
String name = etProductName.getText().toString().trim();
String desc = etProductDesc.getText().toString().trim();
BigDecimal price = new BigDecimal(etProductPrice.getText().toString().trim());
CategoryDTO category = categoryList.get(spinnerCategory.getSelectedItemPosition() - 1);
BigDecimal price;
try {
price = new BigDecimal(priceStr);
} catch (Exception e) {
etProductPrice.setError("Invalid price"); return;
}
ProductDTO dto = new ProductDTO(name, category.getCategoryId(), desc, price);
if (isEditing) {

View File

@@ -14,6 +14,8 @@ import com.example.petstoremobile.adapters.BlackTextArrayAdapter;
import com.example.petstoremobile.api.*;
import com.example.petstoremobile.dtos.*;
import com.example.petstoremobile.utils.ErrorUtils;
import com.example.petstoremobile.utils.InputValidator;
import com.example.petstoremobile.utils.SpinnerUtils;
import java.math.BigDecimal;
import java.util.*;
@@ -92,7 +94,9 @@ public class ProductSupplierDetailFragment extends Fragment {
Response<PageResponse<ProductDTO>> r) {
if (r.isSuccessful() && r.body() != null) {
productList = r.body().getContent();
populateProductSpinner();
SpinnerUtils.populateSpinner(requireContext(), spinnerProduct, productList,
ProductDTO::getProdName, "-- Select Product --",
preselectedProductId, ProductDTO::getProdId);
}
}
public void onFailure(Call<PageResponse<ProductDTO>> c, Throwable t) {
@@ -101,24 +105,6 @@ public class ProductSupplierDetailFragment extends Fragment {
});
}
/**
* Populates the product spinner.
*/
private void populateProductSpinner() {
List<String> names = new ArrayList<>();
names.add("-- Select Product --");
for (ProductDTO p : productList) names.add(p.getProdName());
spinnerProduct.setAdapter(new BlackTextArrayAdapter<>(requireContext(),
android.R.layout.simple_spinner_item, names));
if (preselectedProductId != -1) {
for (int i = 0; i < productList.size(); i++) {
if (productList.get(i).getProdId().equals(preselectedProductId)) {
spinnerProduct.setSelection(i + 1); break;
}
}
}
}
/**
* Loads the list of suppliers from the API.
*/
@@ -129,7 +115,9 @@ public class ProductSupplierDetailFragment extends Fragment {
Response<PageResponse<SupplierDTO>> r) {
if (r.isSuccessful() && r.body() != null) {
supplierList = r.body().getContent();
populateSupplierSpinner();
SpinnerUtils.populateSpinner(requireContext(), spinnerSupplier, supplierList,
SupplierDTO::getSupCompany, "-- Select Supplier --",
preselectedSupplierId, SupplierDTO::getSupId);
}
}
public void onFailure(Call<PageResponse<SupplierDTO>> c, Throwable t) {
@@ -138,24 +126,6 @@ public class ProductSupplierDetailFragment extends Fragment {
});
}
/**
* Populates the supplier spinner.
*/
private void populateSupplierSpinner() {
List<String> names = new ArrayList<>();
names.add("-- Select Supplier --");
for (SupplierDTO s : supplierList) names.add(s.getSupCompany());
spinnerSupplier.setAdapter(new BlackTextArrayAdapter<>(requireContext(),
android.R.layout.simple_spinner_item, names));
if (preselectedSupplierId != -1) {
for (int i = 0; i < supplierList.size(); i++) {
if (supplierList.get(i).getSupId().equals(preselectedSupplierId)) {
spinnerSupplier.setSelection(i + 1); break;
}
}
}
}
/**
* Handles arguments to determine if the fragment is in edit or add mode.
*/
@@ -186,19 +156,15 @@ public class ProductSupplierDetailFragment extends Fragment {
if (spinnerSupplier.getSelectedItemPosition() == 0) {
Toast.makeText(getContext(), "Select a supplier", Toast.LENGTH_SHORT).show(); return;
}
String costStr = etCost.getText().toString().trim();
if (costStr.isEmpty()) {
etCost.setError("Enter cost"); return;
if (!InputValidator.isNotEmpty(etCost, "Cost") ||
!InputValidator.isPositiveDecimal(etCost, "Cost")) {
return;
}
ProductDTO product = productList.get(spinnerProduct.getSelectedItemPosition() - 1);
SupplierDTO supplier = supplierList.get(spinnerSupplier.getSelectedItemPosition() - 1);
BigDecimal cost;
try {
cost = new BigDecimal(costStr);
} catch (Exception e) {
etCost.setError("Invalid cost"); return;
}
BigDecimal cost = new BigDecimal(etCost.getText().toString().trim());
ProductSupplierDTO dto = new ProductSupplierDTO(
product.getProdId(), supplier.getSupId(), cost);

View File

@@ -19,6 +19,7 @@ import com.example.petstoremobile.api.SaleApi;
import com.example.petstoremobile.fragments.listfragments.SaleFragment;
import com.example.petstoremobile.utils.ActivityLogger;
import com.example.petstoremobile.utils.InputValidator;
import com.example.petstoremobile.utils.SpinnerUtils;
import javax.inject.Inject;
@@ -109,13 +110,7 @@ public class RefundDetailFragment extends Fragment {
tvSaleInfo.setTextColor(getResources().getColor(android.R.color.holo_green_dark));
// Pre-select payment method
String payment = getArguments().getString("paymentMethod");
ArrayAdapter<String> adapter = (ArrayAdapter<String>) spinnerRefundPayment.getAdapter();
if (adapter != null && payment != null) {
int pos = adapter.getPosition(payment);
if (pos >= 0)
spinnerRefundPayment.setSelection(pos);
}
SpinnerUtils.setSelectionByValue(spinnerRefundPayment, getArguments().getString("paymentMethod"));
}
}
@@ -134,10 +129,7 @@ public class RefundDetailFragment extends Fragment {
}
private void setupSpinner() {
BlackTextArrayAdapter<String> adapter = new BlackTextArrayAdapter<>(requireContext(),
android.R.layout.simple_spinner_item,
SpinnerUtils.setupStringSpinner(requireContext(), spinnerRefundPayment,
new String[] { "Cash", "Card", "Debit" });
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinnerRefundPayment.setAdapter(adapter);
}
}

View File

@@ -0,0 +1,68 @@
package com.example.petstoremobile.utils;
import android.content.Context;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import com.example.petstoremobile.adapters.BlackTextArrayAdapter;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
/**
* Utility class for Spinners.
*/
public class SpinnerUtils {
/**
* Populates a spinner with a list of items and handles pre-selection.
*/
public static <T> void populateSpinner(Context context, Spinner spinner, List<T> data,
Function<T, String> nameExtractor, String defaultText,
Long preselectedId, Function<T, Long> idExtractor) {
List<String> names = new ArrayList<>();
if (defaultText != null) {
names.add(defaultText);
}
for (T item : data) {
names.add(nameExtractor.apply(item));
}
spinner.setAdapter(new BlackTextArrayAdapter<>(context,
android.R.layout.simple_spinner_item, names));
if (preselectedId != null && preselectedId != -1) {
int offset = (defaultText != null) ? 1 : 0;
for (int i = 0; i < data.size(); i++) {
if (idExtractor.apply(data.get(i)).equals(preselectedId)) {
spinner.setSelection(i + offset);
break;
}
}
}
}
/**
* Sets the selection of a spinner based on a string value.
*/
public static void setSelectionByValue(Spinner spinner, String value) {
if (value == null || spinner.getAdapter() == null) return;
ArrayAdapter<String> adapter = (ArrayAdapter<String>) spinner.getAdapter();
int pos = adapter.getPosition(value);
if (pos >= 0) {
spinner.setSelection(pos);
}
}
/**
* Configures a simple string array spinner.
*/
public static void setupStringSpinner(Context context, Spinner spinner, String[] items) {
BlackTextArrayAdapter<String> adapter = new BlackTextArrayAdapter<>(context,
android.R.layout.simple_spinner_item, items);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);
}
}