diff --git a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/PetFragment.java b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/PetFragment.java index 2aad5eb4..bf6e7e4e 100644 --- a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/PetFragment.java +++ b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/PetFragment.java @@ -23,8 +23,12 @@ import com.example.petstoremobile.adapters.BlackTextArrayAdapter; import com.example.petstoremobile.adapters.PetAdapter; import com.example.petstoremobile.databinding.FragmentPetBinding; import com.example.petstoremobile.dtos.PetDTO; +import com.example.petstoremobile.dtos.StoreDTO; import com.example.petstoremobile.fragments.ListFragment; +import com.example.petstoremobile.utils.Resource; +import com.example.petstoremobile.utils.SpinnerUtils; import com.example.petstoremobile.viewmodels.PetViewModel; +import com.example.petstoremobile.viewmodels.StoreViewModel; import java.util.ArrayList; import java.util.List; @@ -38,22 +42,25 @@ import dagger.hilt.android.AndroidEntryPoint; public class PetFragment extends Fragment implements PetAdapter.OnPetClickListener { private FragmentPetBinding binding; private List petList = new ArrayList<>(); + private List storeList = new ArrayList<>(); private PetAdapter adapter; private PetViewModel viewModel; + private StoreViewModel storeViewModel; @Inject @Named("baseUrl") String baseUrl; /** - * Initializes the fragment and its associated PetViewModel. + * Initializes the fragment and its associated ViewModels. */ @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); viewModel = new ViewModelProvider(this).get(PetViewModel.class); + storeViewModel = new ViewModelProvider(this).get(StoreViewModel.class); } /** - * Sets up the fragment's UI components, including RecyclerView, search, status filter, and swipe-to-refresh. + * Sets up the fragment's UI components, including RecyclerView, filters, and swipe-to-refresh. */ @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, @@ -63,7 +70,10 @@ public class PetFragment extends Fragment implements PetAdapter.OnPetClickListen setupRecyclerView(); setupSearch(); setupStatusFilter(); + setupSpeciesFilter(); + setupStoreFilter(); setupSwipeRefresh(); + setupFilterToggle(); binding.fabAddPet.setOnClickListener(v -> openPetDetails()); @@ -87,16 +97,38 @@ public class PetFragment extends Fragment implements PetAdapter.OnPetClickListen } /** - * Reloads pet data every time the fragment becomes visible. + * Reloads data every time the fragment becomes visible. */ @Override public void onResume() { super.onResume(); loadPetData(); + loadStoreData(); } /** - * Configures the search bar with a for filtering. + * Sets up the filter toggle button to show/hide the filter layout. + */ + private void setupFilterToggle() { + binding.btnToggleFilter.setOnClickListener(v -> { + if (binding.layoutFilter.getVisibility() == View.GONE) { + binding.layoutFilter.setVisibility(View.VISIBLE); + binding.btnToggleFilter.setImageResource(android.R.drawable.ic_menu_close_clear_cancel); + } else { + binding.layoutFilter.setVisibility(View.GONE); + binding.btnToggleFilter.setImageResource(android.R.drawable.ic_menu_search); + + // Reset filters when closing + binding.etSearchPet.setText(""); + binding.spinnerStatus.setSelection(0); + binding.spinnerSpecies.setSelection(0); + binding.spinnerStore.setSelection(0); + } + }); + } + + /** + * Configures the search bar. */ private void setupSearch() { binding.etSearchPet.addTextChangedListener(new TextWatcher() { @@ -122,57 +154,100 @@ public class PetFragment extends Fragment implements PetAdapter.OnPetClickListen public void onItemSelected(AdapterView parent, View view, int position, long id) { loadPetData(); } - - @Override - public void onNothingSelected(AdapterView parent) {} + @Override public void onNothingSelected(AdapterView parent) {} }); } /** - * Sets up the SwipeRefreshLayout to allow manual re-fetching of pet data. + * Configures the species filter spinner with species. + */ + private void setupSpeciesFilter() { + String[] species = {"All Species", "Dog", "Cat", "Bird", "Rabbit", "Fish", "Hamster"}; + BlackTextArrayAdapter adapter = new BlackTextArrayAdapter<>(requireContext(), android.R.layout.simple_spinner_item, species); + adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + binding.spinnerSpecies.setAdapter(adapter); + + binding.spinnerSpecies.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { + @Override + public void onItemSelected(AdapterView parent, View view, int position, long id) { + loadPetData(); + } + @Override public void onNothingSelected(AdapterView parent) {} + }); + } + + /** + * Configures the store filter spinner. + */ + private void setupStoreFilter() { + binding.spinnerStore.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { + @Override + public void onItemSelected(AdapterView parent, View view, int position, long id) { + loadPetData(); + } + @Override public void onNothingSelected(AdapterView parent) {} + }); + } + + /** + * Fetches store data to populate the store filter. + */ + private void loadStoreData() { + storeViewModel.getAllStores(0, 100).observe(getViewLifecycleOwner(), resource -> { + if (resource.status == Resource.Status.SUCCESS && resource.data != null) { + storeList = resource.data.getContent(); + SpinnerUtils.populateSpinner(requireContext(), binding.spinnerStore, storeList, + StoreDTO::getStoreName, "All Stores", -1L, StoreDTO::getStoreId); + } + }); + } + + /** + * Sets up the SwipeRefreshLayout. */ private void setupSwipeRefresh() { binding.swipeRefreshPet.setOnRefreshListener(this::loadPetData); } /** - * Navigates to the pet profile screen for a specific pet. + * Navigates to the pet profile screen. */ private void openPetProfile(int position) { Bundle args = new Bundle(); PetDTO pet = petList.get(position); args.putLong("petId", pet.getPetId()); - NavHostFragment.findNavController(this).navigate(R.id.nav_pet_profile, args); } /** - * Navigates to the pet detail screen. (Only used for adding a new pet on this screen) + * Navigates to the pet detail screen. */ private void openPetDetails() { NavHostFragment.findNavController(this).navigate(R.id.nav_pet_detail); } - /** - * Handles clicks on individual pet items in the list. - */ @Override public void onPetClick(int position) { openPetProfile(position); } /** - * Fetches pet data from the server with filters and updates the UI. + * Fetches pet data from the server with all active filters. */ private void loadPetData() { String query = binding.etSearchPet.getText().toString().trim(); - String status = binding.spinnerStatus.getSelectedItem().toString(); + String status = binding.spinnerStatus.getSelectedItem() != null ? binding.spinnerStatus.getSelectedItem().toString() : "All Statuses"; + String species = binding.spinnerSpecies.getSelectedItem() != null ? binding.spinnerSpecies.getSelectedItem().toString() : "All Species"; - if (status.equals("All Statuses")) { - status = null; + Long storeId = null; + if (binding.spinnerStore.getSelectedItemPosition() > 0 && !storeList.isEmpty()) { + storeId = storeList.get(binding.spinnerStore.getSelectedItemPosition() - 1).getStoreId(); } - viewModel.getAllPets(0, 100, query, status, null, null, "petName").observe(getViewLifecycleOwner(), resource -> { + if (status.equals("All Statuses")) status = null; + if (species.equals("All Species")) species = null; + + viewModel.getAllPets(0, 100, query, status, species, storeId, "petName").observe(getViewLifecycleOwner(), resource -> { if (resource == null) return; switch (resource.status) { @@ -197,7 +272,7 @@ public class PetFragment extends Fragment implements PetAdapter.OnPetClickListen } /** - * Initializes the RecyclerView with a layout manager and adapter for displaying pets. + * Initializes the RecyclerView. */ private void setupRecyclerView() { adapter = new PetAdapter(petList, this); diff --git a/android/app/src/main/res/layout/fragment_pet.xml b/android/app/src/main/res/layout/fragment_pet.xml index 1f625bac..2e79ed1b 100644 --- a/android/app/src/main/res/layout/fragment_pet.xml +++ b/android/app/src/main/res/layout/fragment_pet.xml @@ -29,42 +29,76 @@ android:contentDescription="Open menu"/> + android:textStyle="bold" + android:layout_marginStart="8dp"/> + + + android:visibility="gone" + android:background="@color/white"> + + + + + + + + + android:layout_marginTop="4dp" + android:background="@android:color/transparent"/> +