From 0813bb4b44b91095b14e21ad71dced782b461636 Mon Sep 17 00:00:00 2001 From: Alex <78383757+Lextical@users.noreply.github.com> Date: Tue, 7 Apr 2026 14:55:43 -0600 Subject: [PATCH] Did the same to inventory --- .../adapters/InventoryAdapter.java | 13 +- .../petstoremobile/api/InventoryApi.java | 8 +- .../petstoremobile/dtos/InventoryDTO.java | 21 ++- .../petstoremobile/dtos/InventoryRequest.java | 31 ---- .../InventoryDetailFragment.java | 150 +++++++----------- .../repositories/InventoryRepository.java | 5 +- .../viewmodels/InventoryViewModel.java | 5 +- .../res/layout/fragment_inventory_detail.xml | 39 ++--- .../src/main/res/layout/item_inventory.xml | 29 +--- 9 files changed, 113 insertions(+), 188 deletions(-) delete mode 100644 android/app/src/main/java/com/example/petstoremobile/dtos/InventoryRequest.java diff --git a/android/app/src/main/java/com/example/petstoremobile/adapters/InventoryAdapter.java b/android/app/src/main/java/com/example/petstoremobile/adapters/InventoryAdapter.java index 984ad065..729d1749 100644 --- a/android/app/src/main/java/com/example/petstoremobile/adapters/InventoryAdapter.java +++ b/android/app/src/main/java/com/example/petstoremobile/adapters/InventoryAdapter.java @@ -53,20 +53,15 @@ public class InventoryAdapter extends RecyclerView.Adapter createInventory(@Body InventoryRequest request); + Call createInventory(@Body InventoryDTO request); // PUT /api/v1/inventory/{id} @PUT("api/v1/inventory/{id}") - Call updateInventory(@Path("id") Long id, @Body InventoryRequest request); + Call updateInventory(@Path("id") Long id, @Body InventoryDTO request); // DELETE /api/v1/inventory/{id} @DELETE("api/v1/inventory/{id}") Call deleteInventory(@Path("id") Long id); // DELETE /api/v1/inventory (bulk delete) - @DELETE("api/v1/inventory") + @HTTP(method = "DELETE", path = "api/v1/inventory", hasBody = true) Call bulkDeleteInventory(@Body BulkDeleteRequest request); } diff --git a/android/app/src/main/java/com/example/petstoremobile/dtos/InventoryDTO.java b/android/app/src/main/java/com/example/petstoremobile/dtos/InventoryDTO.java index fe2ec542..ddafd045 100644 --- a/android/app/src/main/java/com/example/petstoremobile/dtos/InventoryDTO.java +++ b/android/app/src/main/java/com/example/petstoremobile/dtos/InventoryDTO.java @@ -6,6 +6,8 @@ public class InventoryDTO { private Long prodId; private String productName; private String categoryName; + private Long storeId; + private String storeName; private Integer quantity; private String createdAt; private String updatedAt; @@ -14,8 +16,9 @@ public class InventoryDTO { } // Constructor for create/update requests (matches InventoryRequest) - public InventoryDTO(Long prodId, Integer quantity) { + public InventoryDTO(Long prodId, Long storeId, Integer quantity) { this.prodId = prodId; + this.storeId = storeId; this.quantity = quantity; } @@ -51,6 +54,22 @@ public class InventoryDTO { this.categoryName = categoryName; } + public Long getStoreId() { + return storeId; + } + + public void setStoreId(Long storeId) { + this.storeId = storeId; + } + + public String getStoreName() { + return storeName; + } + + public void setStoreName(String storeName) { + this.storeName = storeName; + } + public Integer getQuantity() { return quantity; } diff --git a/android/app/src/main/java/com/example/petstoremobile/dtos/InventoryRequest.java b/android/app/src/main/java/com/example/petstoremobile/dtos/InventoryRequest.java deleted file mode 100644 index f84dfb5f..00000000 --- a/android/app/src/main/java/com/example/petstoremobile/dtos/InventoryRequest.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.example.petstoremobile.dtos; - -public class InventoryRequest { - private Long prodId; - private Integer quantity; - - public InventoryRequest() { - } - - public InventoryRequest(Long prodId, Integer quantity) { - this.prodId = prodId; - this.quantity = quantity; - } - - public Long getProdId() { - return prodId; - } - - public void setProdId(Long prodId) { - this.prodId = prodId; - } - - public Integer getQuantity() { - return quantity; - } - - public void setQuantity(Integer quantity) { - this.quantity = quantity; - } -} - diff --git a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/InventoryDetailFragment.java b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/InventoryDetailFragment.java index 1a32df6e..7a729b94 100644 --- a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/InventoryDetailFragment.java +++ b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/InventoryDetailFragment.java @@ -1,14 +1,9 @@ package com.example.petstoremobile.fragments.listfragments.detailfragments; import android.os.Bundle; -import android.os.Handler; -import android.os.Looper; -import android.text.Editable; -import android.text.TextWatcher; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.ArrayAdapter; import android.widget.Toast; import androidx.annotation.NonNull; @@ -18,15 +13,16 @@ import androidx.fragment.app.Fragment; import androidx.lifecycle.ViewModelProvider; import androidx.navigation.fragment.NavHostFragment; -import com.example.petstoremobile.adapters.BlackTextArrayAdapter; import com.example.petstoremobile.databinding.FragmentInventoryDetailBinding; import com.example.petstoremobile.dtos.InventoryDTO; -import com.example.petstoremobile.dtos.InventoryRequest; import com.example.petstoremobile.dtos.ProductDTO; +import com.example.petstoremobile.dtos.StoreDTO; import com.example.petstoremobile.utils.InputValidator; import com.example.petstoremobile.utils.Resource; +import com.example.petstoremobile.utils.SpinnerUtils; import com.example.petstoremobile.viewmodels.InventoryViewModel; import com.example.petstoremobile.viewmodels.ProductViewModel; +import com.example.petstoremobile.viewmodels.StoreViewModel; import java.util.ArrayList; import java.util.List; @@ -43,20 +39,15 @@ public class InventoryDetailFragment extends Fragment { private InventoryViewModel inventoryViewModel; private ProductViewModel productViewModel; + private StoreViewModel storeViewModel; private boolean isEditing = false; private long inventoryId = -1; + private long preselectedStoreId = -1; + private long preselectedProductId = -1; - // The product selected from the dropdown - private ProductDTO selectedProduct = null; - - // For debouncing product search - private final Handler searchHandler = new Handler(Looper.getMainLooper()); - private Runnable searchRunnable; - - // Dropdown list - private final List productSuggestions = new ArrayList<>(); - private ArrayAdapter dropdownAdapter; + private List storeList = new ArrayList<>(); + private List productList = new ArrayList<>(); /** * Initializes the view models. @@ -66,6 +57,7 @@ public class InventoryDetailFragment extends Fragment { super.onCreate(savedInstanceState); inventoryViewModel = new ViewModelProvider(this).get(InventoryViewModel.class); productViewModel = new ViewModelProvider(this).get(ProductViewModel.class); + storeViewModel = new ViewModelProvider(this).get(StoreViewModel.class); } /** @@ -85,94 +77,64 @@ public class InventoryDetailFragment extends Fragment { public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); - setupProductSearch(); + loadSpinnersData(); handleArguments(); binding.btnInventoryBack.setOnClickListener(v -> navigateBack()); binding.btnSaveInventory.setOnClickListener(v -> saveInventory()); binding.btnDeleteInventory.setOnClickListener(v -> confirmDelete()); - - // Setup dropdown adapter - dropdownAdapter = new BlackTextArrayAdapter<>(requireContext(), - android.R.layout.simple_dropdown_item_1line, new ArrayList<>()); - binding.etProductSearch.setAdapter(dropdownAdapter); - binding.etProductSearch.setThreshold(1); // start showing after 1 character } @Override public void onDestroyView() { super.onDestroyView(); - if (searchRunnable != null) { - searchHandler.removeCallbacks(searchRunnable); - } binding = null; } /** - * Sets up the product search dropdown. + * Fetches required data for spinners from the backend. */ - private void setupProductSearch() { - binding.etProductSearch.addTextChangedListener(new TextWatcher() { - @Override public void beforeTextChanged(CharSequence s, int i, int i1, int i2) { - } + private void loadSpinnersData() { + loadStores(); + loadProducts(); + } - @Override public void afterTextChanged(Editable s) { - } - - @Override - public void onTextChanged(CharSequence s, int start, int before, int count) { - // Clear selected product when user is typing again - selectedProduct = null; - binding.tvProductInfo.setVisibility(View.GONE); - - if (searchRunnable != null) - searchHandler.removeCallbacks(searchRunnable); - String query = s.toString().trim(); - if (query.isEmpty()) - return; - - searchRunnable = () -> searchProducts(query); - searchHandler.postDelayed(searchRunnable, 400); - } - }); - - // When user picks an item from the dropdown - binding.etProductSearch.setOnItemClickListener((parent, view, position, id) -> { - if (position < productSuggestions.size()) { - selectedProduct = productSuggestions.get(position); - // Show product details below the search box - binding.tvProductInfo.setText( - "ID: " + selectedProduct.getProdId() - + " • " + selectedProduct.getCategoryName()); - binding.tvProductInfo.setVisibility(View.VISIBLE); + /** + * Loads the list of stores for the spinner. + */ + private void loadStores() { + storeViewModel.getAllStores(0, 100).observe(getViewLifecycleOwner(), resource -> { + if (resource.status == Resource.Status.SUCCESS && resource.data != null) { + storeList = resource.data.getContent(); + refreshStoreSpinner(); } }); } + private void refreshStoreSpinner() { + SpinnerUtils.populateSpinner(requireContext(), binding.spinnerInventoryStore, storeList, + StoreDTO::getStoreName, "-- Select Store --", + preselectedStoreId, StoreDTO::getStoreId); + } + /** - * Searches for products matching the query from the backend. + * Loads the list of products for the spinner. */ - private void searchProducts(String query) { - if (getView() == null) return; - productViewModel.getAllProducts(query, null, 0, 20, "prodName").observe(getViewLifecycleOwner(), resource -> { + private void loadProducts() { + productViewModel.getAllProducts(null, null, 0, 500, "prodName").observe(getViewLifecycleOwner(), resource -> { if (resource.status == Resource.Status.SUCCESS && resource.data != null) { - productSuggestions.clear(); - productSuggestions.addAll(resource.data.getContent()); - - // Build display strings: "Product Name (ID: X)" - List names = new ArrayList<>(); - for (ProductDTO p : productSuggestions) { - names.add(p.getProdName() + " (ID: " + p.getProdId() + ")"); - } - - dropdownAdapter.clear(); - dropdownAdapter.addAll(names); - dropdownAdapter.notifyDataSetChanged(); - binding.etProductSearch.showDropDown(); + productList = resource.data.getContent(); + refreshProductSpinner(); } }); } + private void refreshProductSpinner() { + SpinnerUtils.populateSpinner(requireContext(), binding.spinnerInventoryProduct, productList, + ProductDTO::getProdName, "-- Select Product --", + preselectedProductId, ProductDTO::getProdId); + } + /** * Handles fragment arguments to determine if we are in edit or add mode. */ @@ -193,7 +155,6 @@ public class InventoryDetailFragment extends Fragment { isEditing = false; binding.tvInventoryMode.setText("Add Inventory"); binding.tvInventoryId.setVisibility(View.GONE); - binding.tvProductInfo.setVisibility(View.GONE); binding.btnDeleteInventory.setVisibility(View.GONE); binding.btnSaveInventory.setText("Add"); } @@ -207,20 +168,12 @@ public class InventoryDetailFragment extends Fragment { if (resource == null) return; if (resource.status == Resource.Status.SUCCESS && resource.data != null) { InventoryDTO inv = resource.data; - binding.etProductSearch.setText(inv.getProductName()); binding.etQuantity.setText(String.valueOf(inv.getQuantity())); - - if (inv.getProdId() != null) { - binding.tvProductInfo.setText( - "ID: " + inv.getProdId() - + " • " + inv.getCategoryName()); - binding.tvProductInfo.setVisibility(View.VISIBLE); - - selectedProduct = new ProductDTO(); - selectedProduct.setProdId(inv.getProdId()); - selectedProduct.setProdName(inv.getProductName()); - selectedProduct.setCategoryName(inv.getCategoryName()); - } + preselectedStoreId = inv.getStoreId() != null ? inv.getStoreId() : -1; + preselectedProductId = inv.getProdId() != null ? inv.getProdId() : -1; + + refreshStoreSpinner(); + refreshProductSpinner(); } else if (resource.status == Resource.Status.ERROR) { Toast.makeText(getContext(), "Failed to load inventory: " + resource.message, Toast.LENGTH_SHORT).show(); } @@ -231,9 +184,12 @@ public class InventoryDetailFragment extends Fragment { * Validates input and saves the current inventory item details to the backend. */ private void saveInventory() { - if (selectedProduct == null) { - binding.etProductSearch.setError("Please select a product from the list"); - binding.etProductSearch.requestFocus(); + if (binding.spinnerInventoryStore.getSelectedItemPosition() == 0) { + Toast.makeText(getContext(), "Please select a store", Toast.LENGTH_SHORT).show(); + return; + } + if (binding.spinnerInventoryProduct.getSelectedItemPosition() == 0) { + Toast.makeText(getContext(), "Please select a product", Toast.LENGTH_SHORT).show(); return; } @@ -243,8 +199,10 @@ public class InventoryDetailFragment extends Fragment { } int quantity = Integer.parseInt(binding.etQuantity.getText().toString().trim()); + StoreDTO store = storeList.get(binding.spinnerInventoryStore.getSelectedItemPosition() - 1); + ProductDTO product = productList.get(binding.spinnerInventoryProduct.getSelectedItemPosition() - 1); - InventoryRequest request = new InventoryRequest(selectedProduct.getProdId(), quantity); + InventoryDTO request = new InventoryDTO(product.getProdId(), store.getStoreId(), quantity); setButtonsEnabled(false); if (isEditing) { diff --git a/android/app/src/main/java/com/example/petstoremobile/repositories/InventoryRepository.java b/android/app/src/main/java/com/example/petstoremobile/repositories/InventoryRepository.java index 05719c38..159e4cea 100644 --- a/android/app/src/main/java/com/example/petstoremobile/repositories/InventoryRepository.java +++ b/android/app/src/main/java/com/example/petstoremobile/repositories/InventoryRepository.java @@ -5,7 +5,6 @@ import androidx.lifecycle.LiveData; import com.example.petstoremobile.api.InventoryApi; import com.example.petstoremobile.dtos.BulkDeleteRequest; import com.example.petstoremobile.dtos.InventoryDTO; -import com.example.petstoremobile.dtos.InventoryRequest; import com.example.petstoremobile.dtos.PageResponse; import com.example.petstoremobile.utils.Resource; @@ -39,11 +38,11 @@ public class InventoryRepository extends BaseRepository { /** * Sends a request to the API to create a new inventory record. */ - public LiveData> createInventory(InventoryRequest request) { + public LiveData> createInventory(InventoryDTO request) { return executeCall(inventoryApi.createInventory(request)); } - public LiveData> updateInventory(Long id, InventoryRequest request) { + public LiveData> updateInventory(Long id, InventoryDTO request) { return executeCall(inventoryApi.updateInventory(id, request)); } diff --git a/android/app/src/main/java/com/example/petstoremobile/viewmodels/InventoryViewModel.java b/android/app/src/main/java/com/example/petstoremobile/viewmodels/InventoryViewModel.java index 02a5f1bb..3b5a8507 100644 --- a/android/app/src/main/java/com/example/petstoremobile/viewmodels/InventoryViewModel.java +++ b/android/app/src/main/java/com/example/petstoremobile/viewmodels/InventoryViewModel.java @@ -6,7 +6,6 @@ import androidx.lifecycle.ViewModel; import com.example.petstoremobile.dtos.BulkDeleteRequest; import com.example.petstoremobile.dtos.CategoryDTO; import com.example.petstoremobile.dtos.InventoryDTO; -import com.example.petstoremobile.dtos.InventoryRequest; import com.example.petstoremobile.dtos.PageResponse; import com.example.petstoremobile.dtos.StoreDTO; import com.example.petstoremobile.repositories.CategoryRepository; @@ -50,14 +49,14 @@ public class InventoryViewModel extends ViewModel { /** * Creates a new inventory record. */ - public LiveData> createInventory(InventoryRequest request) { + public LiveData> createInventory(InventoryDTO request) { return inventoryRepository.createInventory(request); } /** * Updates an existing inventory record by ID. */ - public LiveData> updateInventory(Long id, InventoryRequest request) { + public LiveData> updateInventory(Long id, InventoryDTO request) { return inventoryRepository.updateInventory(id, request); } diff --git a/android/app/src/main/res/layout/fragment_inventory_detail.xml b/android/app/src/main/res/layout/fragment_inventory_detail.xml index 09047dc3..77994cac 100644 --- a/android/app/src/main/res/layout/fragment_inventory_detail.xml +++ b/android/app/src/main/res/layout/fragment_inventory_detail.xml @@ -67,7 +67,23 @@ android:layout_marginBottom="12dp" android:visibility="gone"/> - + + + + + + + - - + - - - + android:layout_marginBottom="16dp"/> @@ -55,31 +55,14 @@ - - - - - - + android:textSize="14sp" + android:textStyle="italic" />