From 933a6bff6b378b0a13d7abc4e5004510616f1583 Mon Sep 17 00:00:00 2001 From: Alex <78383757+Lextical@users.noreply.github.com> Date: Sat, 4 Apr 2026 17:16:44 -0600 Subject: [PATCH] Added calendar view to adoptions in andriod --- .../listfragments/AdoptionFragment.java | 97 ++++++++++++++++--- .../src/main/res/layout/fragment_adoption.xml | 22 ++++- 2 files changed, 107 insertions(+), 12 deletions(-) diff --git a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/AdoptionFragment.java b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/AdoptionFragment.java index 34e7d602..c655f78b 100644 --- a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/AdoptionFragment.java +++ b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/AdoptionFragment.java @@ -1,10 +1,12 @@ package com.example.petstoremobile.fragments.listfragments; +import android.graphics.Color; import android.os.Bundle; import android.text.*; import android.util.Log; import android.view.*; import android.widget.*; +import androidx.annotation.NonNull; import androidx.fragment.app.Fragment; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; @@ -17,7 +19,14 @@ import com.example.petstoremobile.dtos.AdoptionDTO; import com.example.petstoremobile.dtos.PageResponse; import com.example.petstoremobile.fragments.ListFragment; import com.example.petstoremobile.fragments.listfragments.detailfragments.AdoptionDetailFragment; +import com.example.petstoremobile.utils.EventDecorator; import com.google.android.material.floatingactionbutton.FloatingActionButton; +import com.prolificinteractive.materialcalendarview.CalendarDay; +import com.prolificinteractive.materialcalendarview.CalendarMode; +import com.prolificinteractive.materialcalendarview.MaterialCalendarView; +import com.prolificinteractive.materialcalendarview.OnDateSelectedListener; +import java.text.ParseException; +import java.text.SimpleDateFormat; import java.util.*; import retrofit2.*; @@ -30,6 +39,11 @@ public class AdoptionFragment extends Fragment implements AdoptionAdapter.OnAdop private SwipeRefreshLayout swipeRefresh; private EditText etSearch; private ImageButton hamburger; + private ImageButton btnToggleCalendarMode; + private MaterialCalendarView calendarView; + private CalendarDay selectedCalendarDay; + private boolean isMonthMode = false; + private final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()); @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, @@ -38,10 +52,13 @@ public class AdoptionFragment extends Fragment implements AdoptionAdapter.OnAdop api = RetrofitClient.getAdoptionApi(requireContext()); hamburger = view.findViewById(R.id.btnHamburgerAdoption); + calendarView = view.findViewById(R.id.calendarViewAdoption); + btnToggleCalendarMode = view.findViewById(R.id.btnToggleCalendarModeAdoption); setupRecyclerView(view); setupSearch(view); setupSwipeRefresh(view); + setupCalendar(); loadAdoptions(); FloatingActionButton fab = view.findViewById(R.id.fabAddAdoption); @@ -52,9 +69,57 @@ public class AdoptionFragment extends Fragment implements AdoptionAdapter.OnAdop if (lf != null) lf.openDrawer(); }); + btnToggleCalendarMode.setOnClickListener(v -> toggleCalendarMode()); + return view; } + private void toggleCalendarMode() { + isMonthMode = !isMonthMode; + calendarView.state().edit() + .setCalendarDisplayMode(isMonthMode ? CalendarMode.MONTHS : CalendarMode.WEEKS) + .commit(); + } + + private void setupCalendar() { + calendarView.setOnDateChangedListener(new OnDateSelectedListener() { + @Override + public void onDateSelected(@NonNull MaterialCalendarView widget, @NonNull CalendarDay date, boolean selected) { + if (selected) { + if (date.equals(selectedCalendarDay)) { + selectedCalendarDay = null; + calendarView.clearSelection(); + } else { + selectedCalendarDay = date; + } + } else { + selectedCalendarDay = null; + } + filter(etSearch.getText().toString()); + } + }); + } + + private void updateCalendarDecorators() { + HashSet datesWithAdoptions = new HashSet<>(); + for (AdoptionDTO adoption : adoptionList) { + try { + if (adoption.getAdoptionDate() != null) { + Date date = dateFormat.parse(adoption.getAdoptionDate()); + if (date != null) { + Calendar cal = Calendar.getInstance(); + cal.setTime(date); + datesWithAdoptions.add(CalendarDay.from(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH) + 1, cal.get(Calendar.DAY_OF_MONTH))); + } + } + } catch (ParseException e) { + Log.e("AdoptionFragment", "Error parsing date: " + adoption.getAdoptionDate()); + } + } + calendarView.removeDecorators(); + calendarView.addDecorator(new EventDecorator(Color.RED, datesWithAdoptions)); + } + private void setupRecyclerView(View view) { RecyclerView rv = view.findViewById(R.id.recyclerViewAdoptions); adapter = new AdoptionAdapter(filteredList, this); @@ -80,16 +145,25 @@ public class AdoptionFragment extends Fragment implements AdoptionAdapter.OnAdop private void filter(String query) { filteredList.clear(); - if (query.isEmpty()) { - filteredList.addAll(adoptionList); - } else { - String lower = query.toLowerCase(); - for (AdoptionDTO a : adoptionList) { - if ((a.getCustomerName() != null && a.getCustomerName().toLowerCase().contains(lower)) - || (a.getPetName() != null && a.getPetName().toLowerCase().contains(lower)) - || (a.getAdoptionStatus() != null && a.getAdoptionStatus().toLowerCase().contains(lower))) { - filteredList.add(a); - } + String lowerQuery = query.toLowerCase(); + + String selectedDateString = null; + if (selectedCalendarDay != null) { + selectedDateString = String.format(Locale.getDefault(), "%04d-%02d-%02d", + selectedCalendarDay.getYear(), selectedCalendarDay.getMonth(), selectedCalendarDay.getDay()); + } + + for (AdoptionDTO a : adoptionList) { + boolean matchesSearch = query.isEmpty() || + (a.getCustomerName() != null && a.getCustomerName().toLowerCase().contains(lowerQuery)) || + (a.getPetName() != null && a.getPetName().toLowerCase().contains(lowerQuery)) || + (a.getAdoptionStatus() != null && a.getAdoptionStatus().toLowerCase().contains(lowerQuery)); + + boolean matchesDate = (selectedDateString == null) || + (a.getAdoptionDate() != null && a.getAdoptionDate().startsWith(selectedDateString)); + + if (matchesSearch && matchesDate) { + filteredList.add(a); } } adapter.notifyDataSetChanged(); @@ -97,13 +171,14 @@ public class AdoptionFragment extends Fragment implements AdoptionAdapter.OnAdop private void loadAdoptions() { if (swipeRefresh != null) swipeRefresh.setRefreshing(true); - api.getAllAdoptions(0, 100).enqueue(new Callback>() { + api.getAllAdoptions(0, 500).enqueue(new Callback>() { public void onResponse(Call> c, Response> r) { if (swipeRefresh != null) swipeRefresh.setRefreshing(false); if (r.isSuccessful() && r.body() != null) { adoptionList.clear(); adoptionList.addAll(r.body().getContent()); + updateCalendarDecorators(); filter(etSearch != null ? etSearch.getText().toString() : ""); } else { Toast.makeText(getContext(), "Failed to load adoptions", Toast.LENGTH_SHORT).show(); diff --git a/android/app/src/main/res/layout/fragment_adoption.xml b/android/app/src/main/res/layout/fragment_adoption.xml index 492b9236..5bc95c38 100644 --- a/android/app/src/main/res/layout/fragment_adoption.xml +++ b/android/app/src/main/res/layout/fragment_adoption.xml @@ -28,15 +28,35 @@ android:contentDescription="Open menu"/> + + + +