Close chat #169

Closed
RecentRunner wants to merge 291 commits from close-chat into main
2 changed files with 141 additions and 32 deletions
Showing only changes of commit 0086bb4a5e - Show all commits

View File

@@ -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<PetDTO> petList = new ArrayList<>();
private List<StoreDTO> 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<String> 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);

View File

@@ -29,42 +29,76 @@
android:contentDescription="Open menu"/>
<TextView
android:layout_width="match_parent"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Pets"
android:textColor="@color/white"
android:textSize="20sp"
android:textStyle="bold"/>
android:textStyle="bold"
android:layout_marginStart="8dp"/>
<ImageButton
android:id="@+id/btnToggleFilter"
android:layout_width="48dp"
android:layout_height="48dp"
android:src="@android:drawable/ic_menu_search"
android:background="?attr/selectableItemBackgroundBorderless"
app:tint="@color/white"
android:contentDescription="Toggle filter"/>
</LinearLayout>
<LinearLayout
android:id="@+id/layoutFilter"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:orientation="vertical"
android:padding="8dp"
android:gravity="center_vertical">
android:visibility="gone"
android:background="@color/white">
<EditText
android:id="@+id/etSearchPet"
android:layout_width="0dp"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_weight="1"
android:hint="Search..."
android:inputType="text"
android:drawableStart="@android:drawable/ic_menu_search"
android:drawablePadding="8dp"
android:background="@android:color/white"
android:background="@android:color/transparent"
android:padding="12dp"
android:textColor="@color/text_dark"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Spinner
android:id="@+id/spinnerStatus"
android:layout_width="0dp"
android:layout_height="48dp"
android:layout_weight="1"
android:background="@android:color/transparent"/>
<Spinner
android:id="@+id/spinnerSpecies"
android:layout_width="0dp"
android:layout_height="48dp"
android:layout_weight="1"
android:layout_marginStart="4dp"
android:background="@android:color/transparent"/>
</LinearLayout>
<Spinner
android:id="@+id/spinnerStatus"
android:layout_width="140dp"
android:id="@+id/spinnerStore"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_marginStart="8dp"
android:background="@android:color/white"
android:padding="10dp"/>
android:layout_marginTop="4dp"
android:background="@android:color/transparent"/>
</LinearLayout>
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout