added calendar view to appointments
- NOTE: may have to change appointments abit after backend is updated
This commit is contained in:
@@ -82,6 +82,8 @@ dependencies {
|
||||
implementation("com.github.bumptech.glide:glide:4.16.0")
|
||||
annotationProcessor("com.github.bumptech.glide:compiler:4.16.0")
|
||||
|
||||
implementation("com.github.prolificinteractive:material-calendarview:2.0.1")
|
||||
|
||||
testImplementation(libs.junit)
|
||||
androidTestImplementation(libs.ext.junit)
|
||||
androidTestImplementation(libs.espresso.core)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.example.petstoremobile.fragments.listfragments;
|
||||
|
||||
import android.graphics.Color;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
@@ -29,10 +30,21 @@ import com.example.petstoremobile.dtos.PageResponse;
|
||||
import com.example.petstoremobile.dtos.PetDTO;
|
||||
import com.example.petstoremobile.fragments.ListFragment;
|
||||
import com.example.petstoremobile.fragments.listfragments.detailfragments.AppointmentDetailFragment;
|
||||
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.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import retrofit2.Call;
|
||||
import retrofit2.Callback;
|
||||
@@ -50,6 +62,11 @@ public class AppointmentFragment extends Fragment implements AppointmentAdapter.
|
||||
private SwipeRefreshLayout swipeRefreshLayout;
|
||||
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,
|
||||
@@ -58,10 +75,13 @@ public class AppointmentFragment extends Fragment implements AppointmentAdapter.
|
||||
|
||||
api = RetrofitClient.getAppointmentApi(requireContext());
|
||||
hamburger = view.findViewById(R.id.btnHamburger);
|
||||
calendarView = view.findViewById(R.id.calendarView);
|
||||
btnToggleCalendarMode = view.findViewById(R.id.btnToggleCalendarMode);
|
||||
|
||||
setupRecyclerView(view);
|
||||
setupSearch(view);
|
||||
setupSwipeRefresh(view);
|
||||
setupCalendar();
|
||||
loadAppointmentData();
|
||||
loadPets();
|
||||
loadServices();
|
||||
@@ -76,9 +96,60 @@ public class AppointmentFragment extends Fragment implements AppointmentAdapter.
|
||||
listFragment.openDrawer();
|
||||
});
|
||||
|
||||
btnToggleCalendarMode.setOnClickListener(v -> toggleCalendarMode());
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
// Toggle Calendar Mode from week to month and other way around
|
||||
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;
|
||||
}
|
||||
filterAppointments(etSearch.getText().toString());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//Set indicators for dates with appointments on the calendar
|
||||
private void updateCalendarDecorators() {
|
||||
HashSet<CalendarDay> datesWithAppointments = new HashSet<>();
|
||||
for (AppointmentDTO appointment : appointmentList) {
|
||||
try {
|
||||
//Get the appointment date
|
||||
Date date = dateFormat.parse(appointment.getAppointmentDate());
|
||||
//if the date is not null, add it to the hashset
|
||||
if (date != null) {
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.setTime(date);
|
||||
datesWithAppointments.add(CalendarDay.from(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH) + 1, cal.get(Calendar.DAY_OF_MONTH)));
|
||||
}
|
||||
} catch (ParseException e) {
|
||||
Log.e("AppointmentFragment", "Error parsing date: " + appointment.getAppointmentDate());
|
||||
}
|
||||
}
|
||||
//update the indicators to the calendar
|
||||
calendarView.removeDecorators();
|
||||
calendarView.addDecorator(new EventDecorator(Color.RED, datesWithAppointments));
|
||||
}
|
||||
|
||||
private void setupSearch(View view) {
|
||||
etSearch = view.findViewById(R.id.etSearchAppointment);
|
||||
etSearch.addTextChangedListener(new TextWatcher() {
|
||||
@@ -99,16 +170,25 @@ public class AppointmentFragment extends Fragment implements AppointmentAdapter.
|
||||
|
||||
private void filterAppointments(String query) {
|
||||
filteredList.clear();
|
||||
if (query.isEmpty()) {
|
||||
filteredList.addAll(appointmentList);
|
||||
} else {
|
||||
String lower = query.toLowerCase();
|
||||
for (AppointmentDTO a : appointmentList) {
|
||||
if ((a.getCustomerName() != null && a.getCustomerName().toLowerCase().contains(lower))
|
||||
|| (a.getServiceType() != null && a.getServiceType().toLowerCase().contains(lower))
|
||||
|| (a.getPetName() != null && a.getPetName().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 (AppointmentDTO a : appointmentList) {
|
||||
boolean matchesSearch = query.isEmpty() ||
|
||||
(a.getCustomerName() != null && a.getCustomerName().toLowerCase().contains(lowerQuery)) ||
|
||||
(a.getServiceType() != null && a.getServiceType().toLowerCase().contains(lowerQuery)) ||
|
||||
(a.getPetName() != null && a.getPetName().toLowerCase().contains(lowerQuery));
|
||||
|
||||
boolean matchesDate = (selectedDateString == null) ||
|
||||
(a.getAppointmentDate() != null && a.getAppointmentDate().equals(selectedDateString));
|
||||
|
||||
if (matchesSearch && matchesDate) {
|
||||
filteredList.add(a);
|
||||
}
|
||||
}
|
||||
adapter.notifyDataSetChanged();
|
||||
@@ -141,17 +221,11 @@ public class AppointmentFragment extends Fragment implements AppointmentAdapter.
|
||||
if (lf != null) lf.loadFragment(detailFragment);
|
||||
}
|
||||
public void onAppointmentSaved(int position, AppointmentDTO appointment) {
|
||||
if (position == -1) {
|
||||
appointmentList.add(appointment);
|
||||
} else {
|
||||
appointmentList.set(position, appointment);
|
||||
}
|
||||
filterAppointments(etSearch.getText().toString());
|
||||
loadAppointmentData();
|
||||
}
|
||||
|
||||
public void onAppointmentDeleted(int position) {
|
||||
appointmentList.remove(position);
|
||||
filterAppointments(etSearch.getText().toString());
|
||||
loadAppointmentData();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -162,7 +236,7 @@ public class AppointmentFragment extends Fragment implements AppointmentAdapter.
|
||||
private void loadAppointmentData() {
|
||||
if (swipeRefreshLayout != null)
|
||||
swipeRefreshLayout.setRefreshing(true);
|
||||
api.getAllAppointments(0, 100).enqueue(new Callback<PageResponse<AppointmentDTO>>() {
|
||||
api.getAllAppointments(0, 500).enqueue(new Callback<PageResponse<AppointmentDTO>>() {
|
||||
@Override
|
||||
public void onResponse(Call<PageResponse<AppointmentDTO>> call,
|
||||
Response<PageResponse<AppointmentDTO>> response) {
|
||||
@@ -171,6 +245,7 @@ public class AppointmentFragment extends Fragment implements AppointmentAdapter.
|
||||
if (response.isSuccessful() && response.body() != null) {
|
||||
appointmentList.clear();
|
||||
appointmentList.addAll(response.body().getContent());
|
||||
updateCalendarDecorators();
|
||||
filterAppointments(etSearch != null ? etSearch.getText().toString() : "");
|
||||
} else {
|
||||
Log.e("AppointmentFragment", "Error: " + response.message());
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.example.petstoremobile.utils;
|
||||
|
||||
import com.prolificinteractive.materialcalendarview.CalendarDay;
|
||||
import com.prolificinteractive.materialcalendarview.DayViewDecorator;
|
||||
import com.prolificinteractive.materialcalendarview.DayViewFacade;
|
||||
import com.prolificinteractive.materialcalendarview.spans.DotSpan;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
|
||||
public class EventDecorator implements DayViewDecorator {
|
||||
|
||||
private final int color;
|
||||
private final HashSet<CalendarDay> dates;
|
||||
|
||||
public EventDecorator(int color, Collection<CalendarDay> dates) {
|
||||
this.color = color;
|
||||
this.dates = new HashSet<>(dates);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldDecorate(CalendarDay day) {
|
||||
return dates.contains(day);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decorate(DayViewFacade view) {
|
||||
view.addSpan(new DotSpan(8, color));
|
||||
}
|
||||
}
|
||||
@@ -29,15 +29,35 @@
|
||||
android:contentDescription="Open menu"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Appointments"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold"/>
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/btnToggleCalendarMode"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:src="@android:drawable/ic_menu_today"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
app:tint="@color/white"
|
||||
android:contentDescription="Toggle Calendar Mode"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<com.prolificinteractive.materialcalendarview.MaterialCalendarView
|
||||
android:id="@+id/calendarView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@android:color/white"
|
||||
app:mcv_showOtherDates="all"
|
||||
app:mcv_selectionColor="@color/accent_blue"
|
||||
app:mcv_calendarMode="week"
|
||||
app:mcv_tileHeight="40dp" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/etSearchAppointment"
|
||||
android:layout_width="match_parent"
|
||||
|
||||
Reference in New Issue
Block a user