Appointments
validation, time slots for booking appointment , date, store. connected to service Type, pet name, customer name. Loads from database
This commit is contained in:
@@ -1,7 +1,5 @@
|
|||||||
package com.example.petstoremobile.adapters;
|
package com.example.petstoremobile.adapters;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
@@ -10,26 +8,24 @@ import android.widget.TextView;
|
|||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
import com.example.petstoremobile.R;
|
import com.example.petstoremobile.R;
|
||||||
import com.example.petstoremobile.models.Appointment;
|
import com.example.petstoremobile.dtos.AppointmentDTO;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class AppointmentAdapter extends RecyclerView.Adapter<AppointmentAdapter.AppointmentViewHolder> {
|
public class AppointmentAdapter extends RecyclerView.Adapter<AppointmentAdapter.AppointmentViewHolder> {
|
||||||
|
|
||||||
private List<Appointment> appointmentList;
|
private List<AppointmentDTO> appointmentList;
|
||||||
private OnAppointmentClickListener appointmentClickListener;
|
private OnAppointmentClickListener appointmentClickListener;
|
||||||
|
|
||||||
// Interface for appointment click on recycler view
|
|
||||||
public interface OnAppointmentClickListener {
|
public interface OnAppointmentClickListener {
|
||||||
void onAppointmentClick(int position);
|
void onAppointmentClick(int position);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Constructor
|
public AppointmentAdapter(List<AppointmentDTO> appointmentList,
|
||||||
public AppointmentAdapter(List<Appointment> appointmentList, OnAppointmentClickListener appointmentClickListener) {
|
OnAppointmentClickListener appointmentClickListener) {
|
||||||
this.appointmentList = appointmentList;
|
this.appointmentList = appointmentList;
|
||||||
this.appointmentClickListener = appointmentClickListener;
|
this.appointmentClickListener = appointmentClickListener;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the controls of each row in recycler view
|
|
||||||
public static class AppointmentViewHolder extends RecyclerView.ViewHolder {
|
public static class AppointmentViewHolder extends RecyclerView.ViewHolder {
|
||||||
TextView tvCustomerName, tvPetName, tvServiceType, tvDateTime, tvAppointmentStatus;
|
TextView tvCustomerName, tvPetName, tvServiceType, tvDateTime, tvAppointmentStatus;
|
||||||
|
|
||||||
@@ -43,7 +39,6 @@ public class AppointmentAdapter extends RecyclerView.Adapter<AppointmentAdapter.
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a new row view
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public AppointmentViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
public AppointmentViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||||
@@ -51,31 +46,34 @@ public class AppointmentAdapter extends RecyclerView.Adapter<AppointmentAdapter.
|
|||||||
return new AppointmentViewHolder(v);
|
return new AppointmentViewHolder(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Populate the row with appointment data
|
|
||||||
@Override
|
@Override
|
||||||
public void onBindViewHolder(@NonNull AppointmentViewHolder holder, int position) {
|
public void onBindViewHolder(@NonNull AppointmentViewHolder holder, int position) {
|
||||||
Appointment appointment = appointmentList.get(position);
|
AppointmentDTO a = appointmentList.get(position);
|
||||||
|
|
||||||
holder.tvCustomerName.setText(appointment.getCustomerName());
|
holder.tvCustomerName.setText(a.getCustomerName() != null ? a.getCustomerName() : "");
|
||||||
holder.tvPetName.setText("Pet: " + appointment.getPetName());
|
holder.tvPetName.setText("Pet: " + (a.getPetName() != null ? a.getPetName() : ""));
|
||||||
holder.tvServiceType.setText(appointment.getServiceType());
|
holder.tvServiceType.setText(a.getServiceType() != null ? a.getServiceType() : "");
|
||||||
holder.tvDateTime.setText(appointment.getAppointmentDate() + " at " + appointment.getAppointmentTime());
|
holder.tvDateTime.setText((a.getAppointmentDate() != null ? a.getAppointmentDate() : "") +
|
||||||
holder.tvAppointmentStatus.setText(appointment.getStatus());
|
" at " + (a.getAppointmentTime() != null ? a.getAppointmentTime() : ""));
|
||||||
|
|
||||||
// Set the status color depending on appointment status
|
String status = a.getStatus() != null ? a.getStatus() : "";
|
||||||
switch (appointment.getStatus()) {
|
holder.tvAppointmentStatus.setText(status);
|
||||||
case "Confirmed":
|
|
||||||
holder.tvAppointmentStatus.setBackgroundColor(Color.parseColor("#4CAF50"));
|
switch (status) {
|
||||||
|
case "Booked":
|
||||||
|
holder.tvAppointmentStatus.setBackgroundColor(Color.parseColor("#2196F3")); // blue
|
||||||
break;
|
break;
|
||||||
case "Pending":
|
case "Completed":
|
||||||
holder.tvAppointmentStatus.setBackgroundColor(Color.parseColor("#FF9800"));
|
holder.tvAppointmentStatus.setBackgroundColor(Color.parseColor("#4CAF50")); // green
|
||||||
|
break;
|
||||||
|
case "Cancelled":
|
||||||
|
holder.tvAppointmentStatus.setBackgroundColor(Color.parseColor("#F44336")); // red
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
holder.tvAppointmentStatus.setBackgroundColor(Color.parseColor("#F44336"));
|
holder.tvAppointmentStatus.setBackgroundColor(Color.parseColor("#9E9E9E")); // gray
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// When a row is clicked, open the detail view
|
|
||||||
holder.itemView.setOnClickListener(v -> appointmentClickListener.onAppointmentClick(position));
|
holder.itemView.setOnClickListener(v -> appointmentClickListener.onAppointmentClick(position));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package com.example.petstoremobile.api;
|
||||||
|
|
||||||
|
import com.example.petstoremobile.dtos.AppointmentDTO;
|
||||||
|
import com.example.petstoremobile.dtos.PageResponse;
|
||||||
|
|
||||||
|
import retrofit2.Call;
|
||||||
|
import retrofit2.http.Body;
|
||||||
|
import retrofit2.http.DELETE;
|
||||||
|
import retrofit2.http.GET;
|
||||||
|
import retrofit2.http.POST;
|
||||||
|
import retrofit2.http.PUT;
|
||||||
|
import retrofit2.http.Path;
|
||||||
|
import retrofit2.http.Query;
|
||||||
|
|
||||||
|
public interface AppointmentApi {
|
||||||
|
|
||||||
|
@GET("api/v1/appointments")
|
||||||
|
Call<PageResponse<AppointmentDTO>> getAllAppointments(
|
||||||
|
@Query("page") int page,
|
||||||
|
@Query("size") int size);
|
||||||
|
|
||||||
|
@GET("api/v1/appointments/{id}")
|
||||||
|
Call<AppointmentDTO> getAppointmentById(@Path("id") Long id);
|
||||||
|
|
||||||
|
@POST("api/v1/appointments")
|
||||||
|
Call<AppointmentDTO> createAppointment(@Body AppointmentDTO appointment);
|
||||||
|
|
||||||
|
@PUT("api/v1/appointments/{id}")
|
||||||
|
Call<AppointmentDTO> updateAppointment(@Path("id") Long id, @Body AppointmentDTO appointment);
|
||||||
|
|
||||||
|
@DELETE("api/v1/appointments/{id}")
|
||||||
|
Call<Void> deleteAppointment(@Path("id") Long id);
|
||||||
|
}
|
||||||
@@ -0,0 +1,120 @@
|
|||||||
|
package com.example.petstoremobile.dtos;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class AppointmentDTO {
|
||||||
|
// Response fields (from server)
|
||||||
|
private Long appointmentId;
|
||||||
|
private Long customerId;
|
||||||
|
private String customerName;
|
||||||
|
private Long storeId;
|
||||||
|
private String storeName;
|
||||||
|
private Long serviceId;
|
||||||
|
private String serviceName;
|
||||||
|
private String appointmentDate;
|
||||||
|
private String appointmentTime;
|
||||||
|
private String appointmentStatus;
|
||||||
|
private List<String> petNames;
|
||||||
|
private List<Long> petIds;
|
||||||
|
private String createdAt;
|
||||||
|
private String updatedAt;
|
||||||
|
|
||||||
|
// Constructor for CREATE/UPDATE request body
|
||||||
|
// Matches AppointmentRequest exactly
|
||||||
|
public AppointmentDTO(Long customerId, Long storeId, Long serviceId,
|
||||||
|
String appointmentDate, String appointmentTime,
|
||||||
|
String appointmentStatus, List<Long> petIds) {
|
||||||
|
this.customerId = customerId;
|
||||||
|
this.storeId = storeId;
|
||||||
|
this.serviceId = serviceId;
|
||||||
|
this.appointmentDate = appointmentDate;
|
||||||
|
this.appointmentTime = appointmentTime;
|
||||||
|
this.appointmentStatus = appointmentStatus;
|
||||||
|
this.petIds = petIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Getters
|
||||||
|
public Long getAppointmentId() {
|
||||||
|
return appointmentId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getCustomerId() {
|
||||||
|
return customerId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCustomerName() {
|
||||||
|
return customerName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getStoreId() {
|
||||||
|
return storeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStoreName() {
|
||||||
|
return storeName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getServiceId() {
|
||||||
|
return serviceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getServiceName() {
|
||||||
|
return serviceName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAppointmentDate() {
|
||||||
|
return appointmentDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAppointmentTime() {
|
||||||
|
return appointmentTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAppointmentStatus() {
|
||||||
|
return appointmentStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getPetNames() {
|
||||||
|
return petNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Long> getPetIds() {
|
||||||
|
return petIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCreatedAt() {
|
||||||
|
return createdAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUpdatedAt() {
|
||||||
|
return updatedAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convenience getters for adapter/list display
|
||||||
|
public String getPetName() {
|
||||||
|
return (petNames != null && !petNames.isEmpty()) ? petNames.get(0) : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getPetID() {
|
||||||
|
return (petIds != null && !petIds.isEmpty()) ? petIds.get(0) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getPetId() {
|
||||||
|
return getPetID();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keep old name so adapter doesn't break
|
||||||
|
public String getServiceType() {
|
||||||
|
return serviceName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getServiceID() {
|
||||||
|
return serviceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Status alias
|
||||||
|
public String getStatus() {
|
||||||
|
return appointmentStatus;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,59 +1,38 @@
|
|||||||
package com.example.petstoremobile.dtos;
|
package com.example.petstoremobile.dtos;
|
||||||
|
|
||||||
import com.google.gson.annotations.SerializedName;
|
|
||||||
|
|
||||||
public class CustomerDTO {
|
public class CustomerDTO {
|
||||||
@SerializedName("customerId")
|
|
||||||
private Long customerId;
|
private Long customerId;
|
||||||
|
|
||||||
private String firstName;
|
private String firstName;
|
||||||
private String lastName;
|
private String lastName;
|
||||||
private String email;
|
private String email;
|
||||||
private String phone;
|
private String createdAt;
|
||||||
|
private String updatedAt;
|
||||||
public CustomerDTO() {}
|
|
||||||
|
|
||||||
public Long getCustomerId() {
|
public Long getCustomerId() {
|
||||||
return customerId;
|
return customerId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCustomerId(Long customerId) {
|
|
||||||
this.customerId = customerId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getFirstName() {
|
public String getFirstName() {
|
||||||
return firstName;
|
return firstName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setFirstName(String firstName) {
|
|
||||||
this.firstName = firstName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getLastName() {
|
public String getLastName() {
|
||||||
return lastName;
|
return lastName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setLastName(String lastName) {
|
|
||||||
this.lastName = lastName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getEmail() {
|
public String getEmail() {
|
||||||
return email;
|
return email;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setEmail(String email) {
|
|
||||||
this.email = email;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getPhone() {
|
|
||||||
return phone;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPhone(String phone) {
|
|
||||||
this.phone = phone;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getFullName() {
|
public String getFullName() {
|
||||||
return (firstName != null ? firstName : "") + " " + (lastName != null ? lastName : "");
|
return firstName + " " + lastName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCreatedAt() {
|
||||||
|
return createdAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUpdatedAt() {
|
||||||
|
return updatedAt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package com.example.petstoremobile.dtos;
|
||||||
|
|
||||||
|
public class StoreDTO {
|
||||||
|
private Long storeId;
|
||||||
|
private String storeName;
|
||||||
|
private String address;
|
||||||
|
private String phone;
|
||||||
|
private String email;
|
||||||
|
private String createdAt;
|
||||||
|
private String updatedAt;
|
||||||
|
|
||||||
|
// Constructor for hardcoded fallback
|
||||||
|
public StoreDTO(Long storeId, String storeName) {
|
||||||
|
this.storeId = storeId;
|
||||||
|
this.storeName = storeName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getStoreId() { return storeId; }
|
||||||
|
public String getStoreName() { return storeName; }
|
||||||
|
public String getAddress() { return address; }
|
||||||
|
public String getPhone() { return phone; }
|
||||||
|
public String getEmail() { return email; }
|
||||||
|
public String getCreatedAt() { return createdAt; }
|
||||||
|
public String getUpdatedAt() { return updatedAt; }
|
||||||
|
}
|
||||||
@@ -21,6 +21,9 @@ import com.example.petstoremobile.fragments.listfragments.AdoptionFragment;
|
|||||||
import com.example.petstoremobile.fragments.listfragments.AppointmentFragment;
|
import com.example.petstoremobile.fragments.listfragments.AppointmentFragment;
|
||||||
import com.example.petstoremobile.fragments.listfragments.InventoryFragment;
|
import com.example.petstoremobile.fragments.listfragments.InventoryFragment;
|
||||||
import com.example.petstoremobile.fragments.listfragments.ProductFragment;
|
import com.example.petstoremobile.fragments.listfragments.ProductFragment;
|
||||||
|
import com.example.petstoremobile.fragments.listfragments.ProductSupplierFragment;
|
||||||
|
import com.example.petstoremobile.fragments.listfragments.PurchaseOrderFragment;
|
||||||
|
import com.example.petstoremobile.fragments.listfragments.SaleFragment;
|
||||||
|
|
||||||
//The Fragment for the displaying the list of entities to be viewed
|
//The Fragment for the displaying the list of entities to be viewed
|
||||||
public class ListFragment extends Fragment {
|
public class ListFragment extends Fragment {
|
||||||
@@ -31,7 +34,7 @@ public class ListFragment extends Fragment {
|
|||||||
|
|
||||||
// Adoptions, Appointments, Inventory, Products
|
// Adoptions, Appointments, Inventory, Products
|
||||||
|
|
||||||
private LinearLayout drawerAdoptions, drawerAppointments, drawerInventory, drawerProducts;
|
private LinearLayout drawerAdoptions, drawerAppointments, drawerInventory, drawerProducts, drawerProductSupplier, drawerPurchaseOrderView, drawerSale;
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -48,6 +51,10 @@ public class ListFragment extends Fragment {
|
|||||||
drawerAppointments = view.findViewById(R.id.drawerAppointments);
|
drawerAppointments = view.findViewById(R.id.drawerAppointments);
|
||||||
drawerInventory = view.findViewById(R.id.drawerInventory);
|
drawerInventory = view.findViewById(R.id.drawerInventory);
|
||||||
drawerProducts = view.findViewById(R.id.drawerProducts);
|
drawerProducts = view.findViewById(R.id.drawerProducts);
|
||||||
|
drawerProductSupplier=view.findViewById(R.id.drawerProductSupplier);
|
||||||
|
drawerSale=view.findViewById(R.id.drawerSale);
|
||||||
|
drawerPurchaseOrderView=view.findViewById(R.id.drawerPurchaseOrderView);
|
||||||
|
|
||||||
|
|
||||||
//needed to disable touches on the innerContainer while the drawer is open
|
//needed to disable touches on the innerContainer while the drawer is open
|
||||||
touchBlocker = view.findViewById(R.id.touchBlocker);
|
touchBlocker = view.findViewById(R.id.touchBlocker);
|
||||||
@@ -108,7 +115,7 @@ public class ListFragment extends Fragment {
|
|||||||
drawerLayout.closeDrawers();
|
drawerLayout.closeDrawers();
|
||||||
});
|
});
|
||||||
|
|
||||||
//Appoinment
|
//Appointment
|
||||||
drawerAppointments.setOnClickListener(v -> {
|
drawerAppointments.setOnClickListener(v -> {
|
||||||
loadFragment(new AppointmentFragment());
|
loadFragment(new AppointmentFragment());
|
||||||
drawerLayout.closeDrawers();
|
drawerLayout.closeDrawers();
|
||||||
@@ -126,6 +133,27 @@ public class ListFragment extends Fragment {
|
|||||||
drawerLayout.closeDrawers();
|
drawerLayout.closeDrawers();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
//ProductSupplier
|
||||||
|
|
||||||
|
drawerProductSupplier.setOnClickListener(v -> {
|
||||||
|
loadFragment(new ProductSupplierFragment());
|
||||||
|
drawerLayout.closeDrawers();
|
||||||
|
});
|
||||||
|
|
||||||
|
//Purchase
|
||||||
|
|
||||||
|
drawerPurchaseOrderView.setOnClickListener(v -> {
|
||||||
|
loadFragment(new PurchaseOrderFragment());
|
||||||
|
drawerLayout.closeDrawers();
|
||||||
|
});
|
||||||
|
|
||||||
|
//Sale
|
||||||
|
|
||||||
|
drawerSale.setOnClickListener(v -> {
|
||||||
|
loadFragment(new SaleFragment());
|
||||||
|
drawerLayout.closeDrawers();
|
||||||
|
});
|
||||||
|
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,35 +1,52 @@
|
|||||||
package com.example.petstoremobile.fragments.listfragments;
|
package com.example.petstoremobile.fragments.listfragments;
|
||||||
|
|
||||||
// Added search/filter bar to filter appointments by customer name or service type.
|
|
||||||
// Added pull-to-refresh using SwipeRefreshLayout.
|
|
||||||
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
||||||
import android.text.Editable;
|
import android.text.Editable;
|
||||||
import android.text.TextWatcher;
|
import android.text.TextWatcher;
|
||||||
|
import android.util.Log;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
import android.widget.ImageButton;
|
import android.widget.ImageButton;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.example.petstoremobile.R;
|
import com.example.petstoremobile.R;
|
||||||
import com.example.petstoremobile.adapters.AppointmentAdapter;
|
import com.example.petstoremobile.adapters.AppointmentAdapter;
|
||||||
|
import com.example.petstoremobile.api.AppointmentApi;
|
||||||
|
import com.example.petstoremobile.api.PetApi;
|
||||||
|
import com.example.petstoremobile.api.ServiceApi;
|
||||||
|
import com.example.petstoremobile.api.RetrofitClient;
|
||||||
|
import com.example.petstoremobile.dtos.AppointmentDTO;
|
||||||
|
import com.example.petstoremobile.dtos.ServiceDTO;
|
||||||
|
import com.example.petstoremobile.dtos.PageResponse;
|
||||||
|
import com.example.petstoremobile.dtos.PetDTO;
|
||||||
import com.example.petstoremobile.fragments.ListFragment;
|
import com.example.petstoremobile.fragments.ListFragment;
|
||||||
import com.example.petstoremobile.fragments.listfragments.detailfragments.AppointmentDetailFragment;
|
import com.example.petstoremobile.fragments.listfragments.detailfragments.AppointmentDetailFragment;
|
||||||
import com.example.petstoremobile.models.Appointment;
|
|
||||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import retrofit2.Call;
|
||||||
|
import retrofit2.Callback;
|
||||||
|
import retrofit2.Response;
|
||||||
|
|
||||||
public class AppointmentFragment extends Fragment implements AppointmentAdapter.OnAppointmentClickListener {
|
public class AppointmentFragment extends Fragment implements AppointmentAdapter.OnAppointmentClickListener {
|
||||||
|
|
||||||
private List<Appointment> appointmentList = new ArrayList<>(); // full data list
|
private List<AppointmentDTO> appointmentList = new ArrayList<>();
|
||||||
private List<Appointment> filteredList = new ArrayList<>(); // filtered display list
|
private List<AppointmentDTO> filteredList = new ArrayList<>();
|
||||||
|
private List<PetDTO> petList = new ArrayList<>();
|
||||||
|
private List<ServiceDTO> serviceList = new ArrayList<>();
|
||||||
|
|
||||||
private AppointmentAdapter adapter;
|
private AppointmentAdapter adapter;
|
||||||
|
private AppointmentApi api;
|
||||||
private SwipeRefreshLayout swipeRefreshLayout;
|
private SwipeRefreshLayout swipeRefreshLayout;
|
||||||
private EditText etSearch;
|
private EditText etSearch;
|
||||||
private ImageButton hamburger;
|
private ImageButton hamburger;
|
||||||
@@ -39,51 +56,57 @@ public class AppointmentFragment extends Fragment implements AppointmentAdapter.
|
|||||||
Bundle savedInstanceState) {
|
Bundle savedInstanceState) {
|
||||||
View view = inflater.inflate(R.layout.fragment_appointment, container, false);
|
View view = inflater.inflate(R.layout.fragment_appointment, container, false);
|
||||||
|
|
||||||
|
api = RetrofitClient.getAppointmentApi(requireContext());
|
||||||
hamburger = view.findViewById(R.id.btnHamburger);
|
hamburger = view.findViewById(R.id.btnHamburger);
|
||||||
|
|
||||||
loadAppointmentData(); // TODO: Replace with actual API call when backend is ready
|
|
||||||
setupRecyclerView(view);
|
setupRecyclerView(view);
|
||||||
setupSearch(view);
|
setupSearch(view);
|
||||||
setupSwipeRefresh(view);
|
setupSwipeRefresh(view);
|
||||||
|
loadAppointmentData();
|
||||||
|
loadPets();
|
||||||
|
loadServices();
|
||||||
|
|
||||||
FloatingActionButton fabAddAppointment = view.findViewById(R.id.fabAddAppointment);
|
|
||||||
fabAddAppointment.setOnClickListener(v -> openAppointmentDetails(-1));
|
|
||||||
|
|
||||||
//Make the hamburger button open the drawer from listFragment
|
FloatingActionButton fabAdd = view.findViewById(R.id.fabAddAppointment);
|
||||||
|
fabAdd.setOnClickListener(v -> openAppointmentDetails(-1));
|
||||||
|
|
||||||
hamburger.setOnClickListener(v -> {
|
hamburger.setOnClickListener(v -> {
|
||||||
ListFragment listFragment = (ListFragment) getParentFragment();
|
ListFragment listFragment = (ListFragment) getParentFragment();
|
||||||
//if list fragment is found then use its helper function to open the drawer
|
if (listFragment != null)
|
||||||
if (listFragment != null) {
|
|
||||||
listFragment.openDrawer();
|
listFragment.openDrawer();
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sets up the search bar to filter appointments by customer name or service type
|
|
||||||
private void setupSearch(View view) {
|
private void setupSearch(View view) {
|
||||||
etSearch = view.findViewById(R.id.etSearchAppointment);
|
etSearch = view.findViewById(R.id.etSearchAppointment);
|
||||||
etSearch.addTextChangedListener(new TextWatcher() {
|
etSearch.addTextChangedListener(new TextWatcher() {
|
||||||
@Override public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
|
@Override
|
||||||
@Override public void onTextChanged(CharSequence s, int start, int before, int count) {
|
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||||
filterAppointments(s.toString());
|
filterAppointments(s.toString());
|
||||||
}
|
}
|
||||||
@Override public void afterTextChanged(Editable s) {}
|
|
||||||
|
@Override
|
||||||
|
public void afterTextChanged(Editable s) {
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filters the appointment list based on the search query
|
|
||||||
private void filterAppointments(String query) {
|
private void filterAppointments(String query) {
|
||||||
filteredList.clear();
|
filteredList.clear();
|
||||||
if (query.isEmpty()) {
|
if (query.isEmpty()) {
|
||||||
filteredList.addAll(appointmentList);
|
filteredList.addAll(appointmentList);
|
||||||
} else {
|
} else {
|
||||||
String lower = query.toLowerCase();
|
String lower = query.toLowerCase();
|
||||||
for (Appointment a : appointmentList) {
|
for (AppointmentDTO a : appointmentList) {
|
||||||
if (a.getCustomerName().toLowerCase().contains(lower)
|
if ((a.getCustomerName() != null && a.getCustomerName().toLowerCase().contains(lower))
|
||||||
|| a.getServiceType().toLowerCase().contains(lower)
|
|| (a.getServiceType() != null && a.getServiceType().toLowerCase().contains(lower))
|
||||||
|| a.getPetName().toLowerCase().contains(lower)) {
|
|| (a.getPetName() != null && a.getPetName().toLowerCase().contains(lower))) {
|
||||||
filteredList.add(a);
|
filteredList.add(a);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -91,43 +114,33 @@ public class AppointmentFragment extends Fragment implements AppointmentAdapter.
|
|||||||
adapter.notifyDataSetChanged();
|
adapter.notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sets up pull-to-refresh: reloads data when user swipes down
|
|
||||||
private void setupSwipeRefresh(View view) {
|
private void setupSwipeRefresh(View view) {
|
||||||
swipeRefreshLayout = view.findViewById(R.id.swipeRefreshAppointment);
|
swipeRefreshLayout = view.findViewById(R.id.swipeRefreshAppointment);
|
||||||
swipeRefreshLayout.setOnRefreshListener(() -> {
|
swipeRefreshLayout.setOnRefreshListener(this::loadAppointmentData);
|
||||||
loadAppointmentData(); // TODO: Replace with actual API call when backend is ready
|
|
||||||
filterAppointments(etSearch.getText().toString());
|
|
||||||
swipeRefreshLayout.setRefreshing(false);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void openAppointmentDetails(int position) {
|
private void openAppointmentDetails(int position) {
|
||||||
AppointmentDetailFragment detailFragment = new AppointmentDetailFragment();
|
AppointmentDetailFragment detailFragment = new AppointmentDetailFragment();
|
||||||
Bundle args = new Bundle();
|
Bundle args = new Bundle();
|
||||||
args.putInt("position", position);
|
|
||||||
|
|
||||||
if (position != -1) {
|
if (position != -1) {
|
||||||
Appointment appointment = filteredList.get(position);
|
AppointmentDTO a = filteredList.get(position);
|
||||||
// Find the real position in the full list for save/delete callbacks
|
args.putLong("appointmentId", a.getAppointmentId());
|
||||||
int realPosition = appointmentList.indexOf(appointment);
|
args.putString("appointmentDate", a.getAppointmentDate());
|
||||||
args.putInt("position", realPosition);
|
args.putString("appointmentTime", a.getAppointmentTime());
|
||||||
args.putInt("appointmentId", appointment.getAppointmentId());
|
args.putString("appointmentStatus", a.getAppointmentStatus());
|
||||||
args.putString("customerName", appointment.getCustomerName());
|
// IDs for pre-selecting spinners
|
||||||
args.putString("petName", appointment.getPetName());
|
if (a.getPetID() != null) args.putLong("petId", a.getPetID());
|
||||||
args.putString("serviceType", appointment.getServiceType());
|
if (a.getServiceId() != null) args.putLong("serviceId", a.getServiceId());
|
||||||
args.putString("appointmentDate", appointment.getAppointmentDate());
|
if (a.getCustomerId() != null) args.putLong("customerId", a.getCustomerId());
|
||||||
args.putString("appointmentTime", appointment.getAppointmentTime());
|
if (a.getStoreId() != null) args.putLong("storeId", a.getStoreId());
|
||||||
args.putString("status", appointment.getStatus());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
detailFragment.setArguments(args);
|
detailFragment.setArguments(args);
|
||||||
detailFragment.setAppointmentFragment(this);
|
ListFragment lf = (ListFragment) getParentFragment();
|
||||||
|
if (lf != null) lf.loadFragment(detailFragment);
|
||||||
ListFragment listFragment = (ListFragment) getParentFragment();
|
|
||||||
if (listFragment != null) listFragment.loadFragment(detailFragment);
|
|
||||||
}
|
}
|
||||||
|
public void onAppointmentSaved(int position, AppointmentDTO appointment) {
|
||||||
public void onAppointmentSaved(int position, Appointment appointment) {
|
|
||||||
if (position == -1) {
|
if (position == -1) {
|
||||||
appointmentList.add(appointment);
|
appointmentList.add(appointment);
|
||||||
} else {
|
} else {
|
||||||
@@ -146,21 +159,100 @@ public class AppointmentFragment extends Fragment implements AppointmentAdapter.
|
|||||||
openAppointmentDetails(position);
|
openAppointmentDetails(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper function to load hardcoded sample data
|
|
||||||
// Replace with API call
|
|
||||||
private void loadAppointmentData() {
|
private void loadAppointmentData() {
|
||||||
appointmentList.clear();
|
if (swipeRefreshLayout != null)
|
||||||
appointmentList.add(new Appointment(1, "John Smith", "Buddy", "Grooming", "2026-03-10", "10:00 AM", "Confirmed"));
|
swipeRefreshLayout.setRefreshing(true);
|
||||||
appointmentList.add(new Appointment(2, "Jane Doe", "Luna", "Vet Checkup", "2026-03-11", "02:00 PM", "Pending"));
|
api.getAllAppointments(0, 100).enqueue(new Callback<PageResponse<AppointmentDTO>>() {
|
||||||
appointmentList.add(new Appointment(3, "Bob Lee", "Max", "Training", "2026-03-12", "11:00 AM", "Confirmed"));
|
@Override
|
||||||
appointmentList.add(new Appointment(4, "Alice Brown", "Milo", "Grooming", "2026-03-13", "03:00 PM", "Cancelled"));
|
public void onResponse(Call<PageResponse<AppointmentDTO>> call,
|
||||||
filteredList.clear();
|
Response<PageResponse<AppointmentDTO>> response) {
|
||||||
filteredList.addAll(appointmentList);
|
if (swipeRefreshLayout != null)
|
||||||
|
swipeRefreshLayout.setRefreshing(false);
|
||||||
|
if (response.isSuccessful() && response.body() != null) {
|
||||||
|
appointmentList.clear();
|
||||||
|
appointmentList.addAll(response.body().getContent());
|
||||||
|
filterAppointments(etSearch != null ? etSearch.getText().toString() : "");
|
||||||
|
} else {
|
||||||
|
Log.e("AppointmentFragment", "Error: " + response.message());
|
||||||
|
Toast.makeText(getContext(), "Failed to load appointments", Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Call<PageResponse<AppointmentDTO>> call, Throwable t) {
|
||||||
|
if (swipeRefreshLayout != null)
|
||||||
|
swipeRefreshLayout.setRefreshing(false);
|
||||||
|
Toast.makeText(getContext(), "Network error: " + t.getMessage(), Toast.LENGTH_SHORT).show();
|
||||||
|
Log.e("AppointmentFragment", t.getMessage());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Load Pets
|
||||||
|
private void loadPets() {
|
||||||
|
PetApi petApi = RetrofitClient.getPetApi(requireContext());
|
||||||
|
petApi.getAllPets(0,100).enqueue(new Callback<PageResponse<PetDTO>>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResponse(Call<PageResponse<PetDTO>> call, Response<PageResponse<PetDTO>> response) {
|
||||||
|
if (response.isSuccessful() && response.body() !=null) {
|
||||||
|
petList.clear();
|
||||||
|
petList.addAll(response.body().getContent());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Call<PageResponse<PetDTO>> call, Throwable t) {
|
||||||
|
|
||||||
|
Log.e("AppointmentFragment", "Pet load error:" + t.getMessage());
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load Services
|
||||||
|
|
||||||
|
private void loadServices() {
|
||||||
|
ServiceApi serviceApi = RetrofitClient.getServiceApi(requireContext());
|
||||||
|
|
||||||
|
serviceApi.getAllServices(0,100).enqueue(new Callback<PageResponse<ServiceDTO>>() {
|
||||||
|
@Override
|
||||||
|
public void onResponse(Call<PageResponse<ServiceDTO>> call, Response<PageResponse<ServiceDTO>> response) {
|
||||||
|
if (response.isSuccessful() && response.body() != null) {
|
||||||
|
serviceList.clear();
|
||||||
|
serviceList.addAll(response.body().getContent());
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Call<PageResponse<ServiceDTO>> call, Throwable t) {
|
||||||
|
Log.e("AppointmentFragmnet", "Service load error: " + t.getMessage());
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getPetName(Long id) {
|
||||||
|
for (PetDTO p : petList) {
|
||||||
|
if (p.getPetId().equals(id)) return p.getPetName();
|
||||||
|
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getServiceName(Long id) {
|
||||||
|
for (ServiceDTO s : serviceList) {
|
||||||
|
if (s.getServiceId().equals(id))return s.getServiceName();
|
||||||
|
}
|
||||||
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupRecyclerView(View view) {
|
private void setupRecyclerView(View view) {
|
||||||
RecyclerView recyclerView = view.findViewById(R.id.recyclerViewAppointments);
|
RecyclerView recyclerView = view.findViewById(R.id.recyclerViewAppointments);
|
||||||
adapter = new AppointmentAdapter(filteredList, this); // adapter uses filteredList
|
adapter = new AppointmentAdapter(filteredList, this);
|
||||||
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
|
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
|
||||||
recyclerView.setAdapter(adapter);
|
recyclerView.setAdapter(adapter);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,178 +1,443 @@
|
|||||||
package com.example.petstoremobile.fragments.listfragments.detailfragments;
|
package com.example.petstoremobile.fragments.listfragments.detailfragments;
|
||||||
|
|
||||||
|
import android.app.DatePickerDialog;
|
||||||
// Uses InputValidator for detailed field validation and ActivityLogger to log all changes.
|
|
||||||
|
|
||||||
import android.content.res.Configuration;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.*;
|
||||||
|
import android.widget.*;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
import androidx.core.content.ContextCompat;
|
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.ArrayAdapter;
|
|
||||||
import android.widget.Button;
|
|
||||||
import android.widget.EditText;
|
|
||||||
import android.widget.Spinner;
|
|
||||||
import android.widget.TextView;
|
|
||||||
import android.widget.Toast;
|
|
||||||
import com.example.petstoremobile.R;
|
import com.example.petstoremobile.R;
|
||||||
|
import com.example.petstoremobile.api.*;
|
||||||
|
import com.example.petstoremobile.dtos.*;
|
||||||
import com.example.petstoremobile.fragments.ListFragment;
|
import com.example.petstoremobile.fragments.ListFragment;
|
||||||
import com.example.petstoremobile.fragments.listfragments.AppointmentFragment;
|
import java.util.*;
|
||||||
import com.example.petstoremobile.models.Appointment;
|
import retrofit2.*;
|
||||||
import com.example.petstoremobile.utils.ActivityLogger;
|
|
||||||
import com.example.petstoremobile.utils.InputValidator;
|
|
||||||
|
|
||||||
public class AppointmentDetailFragment extends Fragment {
|
public class AppointmentDetailFragment extends Fragment {
|
||||||
|
|
||||||
private TextView tvMode, tvAppointmentId;
|
private TextView tvMode, tvAppointmentId;
|
||||||
private EditText etCustomerName, etPetName, etServiceType, etAppointmentDate, etAppointmentTime;
|
private EditText etAppointmentDate;
|
||||||
private Spinner spinnerStatus;
|
private Spinner spinnerPet, spinnerService, spinnerStatus, spinnerHour, spinnerMinute;
|
||||||
private Button btnSaveAppointment, btnDeleteAppointment, btnBack;
|
private Spinner spinnerCustomer, spinnerStore;
|
||||||
private int appointmentId;
|
private Button btnSave, btnDelete, btnBack;
|
||||||
private int position;
|
|
||||||
private boolean isEditing = false;
|
|
||||||
private AppointmentFragment appointmentFragment;
|
|
||||||
|
|
||||||
// Set the appointment fragment as parent so we refer back when save or delete is done
|
private long appointmentId = -1;
|
||||||
public void setAppointmentFragment(AppointmentFragment fragment) {
|
private boolean isEditing = false;
|
||||||
this.appointmentFragment = fragment;
|
private long preselectedPetId = -1;
|
||||||
}
|
private long preselectedServiceId = -1;
|
||||||
|
private long preselectedCustomerId = -1;
|
||||||
|
private long preselectedStoreId = -1;
|
||||||
|
|
||||||
|
private List<PetDTO> petList = new ArrayList<>();
|
||||||
|
private List<ServiceDTO> serviceList = new ArrayList<>();
|
||||||
|
private List<CustomerDTO> customerList = new ArrayList<>();
|
||||||
|
private List<StoreDTO> storeList = new ArrayList<>();
|
||||||
|
private List<AppointmentDTO> allAppointments = new ArrayList<>();
|
||||||
|
|
||||||
|
private final Integer[] HOURS = {9,10,11,12,13,14,15,16,17};
|
||||||
|
private final Integer[] MINUTES = {0,15,30,45};
|
||||||
|
private final String[] STATUSES = {"Booked","Completed","Cancelled"};
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||||
Bundle savedInstanceState) {
|
|
||||||
View view = inflater.inflate(R.layout.fragment_appointment_detail, container, false);
|
View view = inflater.inflate(R.layout.fragment_appointment_detail, container, false);
|
||||||
|
|
||||||
initViews(view);
|
initViews(view);
|
||||||
setupSpinner();
|
setupSpinners();
|
||||||
|
setupDatePicker();
|
||||||
|
loadData();
|
||||||
handleArguments();
|
handleArguments();
|
||||||
|
|
||||||
btnBack.setOnClickListener(v -> {
|
btnBack.setOnClickListener(v -> navigateBack());
|
||||||
ListFragment listFragment = (ListFragment) getParentFragment();
|
btnSave.setOnClickListener(v -> saveAppointment());
|
||||||
if (listFragment != null) {
|
btnDelete.setOnClickListener(v -> confirmDelete());
|
||||||
listFragment.getChildFragmentManager().popBackStack();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
btnSaveAppointment.setOnClickListener(v -> saveAppointment());
|
|
||||||
btnDeleteAppointment.setOnClickListener(v -> deleteAppointment());
|
|
||||||
|
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validates all fields using InputValidator, then saves the appointment
|
private void initViews(View v) {
|
||||||
private void saveAppointment() {
|
tvMode = v.findViewById(R.id.tvApptMode);
|
||||||
// Validate all inputs using InputValidator utility
|
tvAppointmentId = v.findViewById(R.id.tvAppointmentId);
|
||||||
if (!InputValidator.isNotEmpty(etCustomerName, "Customer Name")) return;
|
etAppointmentDate= v.findViewById(R.id.etAppointmentDate);
|
||||||
if (!InputValidator.isNotEmpty(etPetName, "Pet Name")) return;
|
spinnerPet = v.findViewById(R.id.spinnerPet);
|
||||||
if (!InputValidator.isNotEmpty(etServiceType, "Service Type")) return;
|
spinnerService = v.findViewById(R.id.spinnerService);
|
||||||
if (!InputValidator.isValidDate(etAppointmentDate)) return;
|
spinnerStatus = v.findViewById(R.id.spinnerAppointmentStatus);
|
||||||
if (!InputValidator.isValidTime(etAppointmentTime)) return;
|
spinnerHour = v.findViewById(R.id.spinnerHour);
|
||||||
|
spinnerMinute = v.findViewById(R.id.spinnerMinute);
|
||||||
|
spinnerCustomer = v.findViewById(R.id.spinnerCustomer);
|
||||||
|
spinnerStore = v.findViewById(R.id.spinnerStore);
|
||||||
|
btnSave = v.findViewById(R.id.btnSaveAppointment);
|
||||||
|
btnDelete = v.findViewById(R.id.btnDeleteAppointment);
|
||||||
|
btnBack = v.findViewById(R.id.btnApptBack);
|
||||||
|
}
|
||||||
|
|
||||||
String customerName = etCustomerName.getText().toString().trim();
|
private void setupSpinners() {
|
||||||
String petName = etPetName.getText().toString().trim();
|
spinnerStatus.setAdapter(new ArrayAdapter<>(requireContext(),
|
||||||
String serviceType = etServiceType.getText().toString().trim();
|
android.R.layout.simple_spinner_item, STATUSES));
|
||||||
String date = etAppointmentDate.getText().toString().trim();
|
|
||||||
String time = etAppointmentTime.getText().toString().trim();
|
|
||||||
String status = spinnerStatus.getSelectedItem().toString();
|
|
||||||
|
|
||||||
try {
|
String[] hours = new String[HOURS.length];
|
||||||
if (isEditing) {
|
for (int i = 0; i < HOURS.length; i++)
|
||||||
// TODO: Replace with actual API PUT call when backend is ready
|
hours[i] = String.format("%02d:00", HOURS[i]);
|
||||||
Appointment updated = new Appointment(appointmentId, customerName, petName, serviceType, date, time, status);
|
spinnerHour.setAdapter(new ArrayAdapter<>(requireContext(),
|
||||||
if (appointmentFragment != null) appointmentFragment.onAppointmentSaved(position, updated);
|
android.R.layout.simple_spinner_item, hours));
|
||||||
ActivityLogger.logChange(requireContext(), "Appointment", "UPDATED", appointmentId);
|
spinnerMinute.setAdapter(new ArrayAdapter<>(requireContext(),
|
||||||
Toast.makeText(getContext(), "Appointment updated.", Toast.LENGTH_SHORT).show();
|
android.R.layout.simple_spinner_item, new String[]{"00","15","30","45"}));
|
||||||
} else {
|
}
|
||||||
// TODO: Replace with actual API POST call when backend is ready
|
|
||||||
Appointment newAppt = new Appointment(0, customerName, petName, serviceType, date, time, status);
|
private void setupDatePicker() {
|
||||||
if (appointmentFragment != null) appointmentFragment.onAppointmentSaved(-1, newAppt);
|
etAppointmentDate.setOnClickListener(v -> {
|
||||||
ActivityLogger.log(requireContext(), "Added new Appointment for customer: " + customerName);
|
Calendar c = Calendar.getInstance();
|
||||||
Toast.makeText(getContext(), "Appointment added.", Toast.LENGTH_SHORT).show();
|
DatePickerDialog d = new DatePickerDialog(requireContext(),
|
||||||
|
(dp,y,m,d1) -> etAppointmentDate.setText(
|
||||||
|
String.format("%04d-%02d-%02d", y, m+1, d1)),
|
||||||
|
c.get(Calendar.YEAR), c.get(Calendar.MONTH),
|
||||||
|
c.get(Calendar.DAY_OF_MONTH));
|
||||||
|
d.getDatePicker().setMinDate(System.currentTimeMillis() - 1000);
|
||||||
|
d.show();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadData() {
|
||||||
|
loadPets();
|
||||||
|
loadServices();
|
||||||
|
loadCustomers();
|
||||||
|
loadStores();
|
||||||
|
loadAllAppointments();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadPets() {
|
||||||
|
RetrofitClient.getPetApi(requireContext()).getAllPets(0, 200)
|
||||||
|
.enqueue(new Callback<PageResponse<PetDTO>>() {
|
||||||
|
public void onResponse(Call<PageResponse<PetDTO>> c, Response<PageResponse<PetDTO>> r) {
|
||||||
|
if (r.isSuccessful() && r.body() != null) {
|
||||||
|
petList = r.body().getContent();
|
||||||
|
populatePetSpinner();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void onFailure(Call<PageResponse<PetDTO>> c, Throwable t) {
|
||||||
|
Log.e("APPT", "Pet load failed: " + t.getMessage());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void populatePetSpinner() {
|
||||||
|
List<String> names = new ArrayList<>();
|
||||||
|
names.add("-- Select Pet --");
|
||||||
|
for (PetDTO p : petList) names.add(p.getPetName());
|
||||||
|
spinnerPet.setAdapter(new ArrayAdapter<>(requireContext(),
|
||||||
|
android.R.layout.simple_spinner_item, names));
|
||||||
|
if (preselectedPetId != -1) {
|
||||||
|
for (int i = 0; i < petList.size(); i++) {
|
||||||
|
if (petList.get(i).getPetId().equals(preselectedPetId)) {
|
||||||
|
spinnerPet.setSelection(i + 1); break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Go back to list
|
|
||||||
ListFragment listFragment = (ListFragment) getParentFragment();
|
|
||||||
if (listFragment != null) listFragment.getChildFragmentManager().popBackStack();
|
|
||||||
} catch (Exception e) {
|
|
||||||
ActivityLogger.logException(requireContext(), "AppointmentDetailFragment.saveAppointment", e);
|
|
||||||
Toast.makeText(getContext(), "Error saving appointment.", Toast.LENGTH_SHORT).show();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deletes the appointment and logs the action
|
private void loadServices() {
|
||||||
private void deleteAppointment() {
|
RetrofitClient.getServiceApi(requireContext()).getAllServices(0, 200)
|
||||||
try {
|
.enqueue(new Callback<PageResponse<ServiceDTO>>() {
|
||||||
// TODO: Replace with actual API DELETE call when backend is ready
|
public void onResponse(Call<PageResponse<ServiceDTO>> c, Response<PageResponse<ServiceDTO>> r) {
|
||||||
if (appointmentFragment != null) appointmentFragment.onAppointmentDeleted(position);
|
if (r.isSuccessful() && r.body() != null) {
|
||||||
ActivityLogger.logChange(requireContext(), "Appointment", "DELETED", appointmentId);
|
serviceList = r.body().getContent();
|
||||||
Toast.makeText(getContext(), "Appointment deleted.", Toast.LENGTH_SHORT).show();
|
populateServiceSpinner();
|
||||||
ListFragment listFragment = (ListFragment) getParentFragment();
|
}
|
||||||
if (listFragment != null) listFragment.getChildFragmentManager().popBackStack();
|
}
|
||||||
} catch (Exception e) {
|
public void onFailure(Call<PageResponse<ServiceDTO>> c, Throwable t) {
|
||||||
ActivityLogger.logException(requireContext(), "AppointmentDetailFragment.deleteAppointment", e);
|
Log.e("APPT", "Service load failed: " + t.getMessage());
|
||||||
Toast.makeText(getContext(), "Error deleting appointment.", Toast.LENGTH_SHORT).show();
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void populateServiceSpinner() {
|
||||||
|
List<String> names = new ArrayList<>();
|
||||||
|
names.add("-- Select Service --");
|
||||||
|
for (ServiceDTO s : serviceList) names.add(s.getServiceName());
|
||||||
|
spinnerService.setAdapter(new ArrayAdapter<>(requireContext(),
|
||||||
|
android.R.layout.simple_spinner_item, names));
|
||||||
|
if (preselectedServiceId != -1) {
|
||||||
|
for (int i = 0; i < serviceList.size(); i++) {
|
||||||
|
if (serviceList.get(i).getServiceId().equals(preselectedServiceId)) {
|
||||||
|
spinnerService.setSelection(i + 1); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determines if the fragment is in add or edit mode and populates fields accordingly
|
private void loadCustomers() {
|
||||||
|
RetrofitClient.getCustomerApi(requireContext()).getAllCustomers(0, 200)
|
||||||
|
.enqueue(new Callback<PageResponse<CustomerDTO>>() {
|
||||||
|
public void onResponse(Call<PageResponse<CustomerDTO>> c, Response<PageResponse<CustomerDTO>> r) {
|
||||||
|
if (r.isSuccessful() && r.body() != null) {
|
||||||
|
customerList = r.body().getContent();
|
||||||
|
populateCustomerSpinner();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void onFailure(Call<PageResponse<CustomerDTO>> c, Throwable t) {
|
||||||
|
Log.e("APPT", "Customer load failed: " + t.getMessage());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void populateCustomerSpinner() {
|
||||||
|
List<String> names = new ArrayList<>();
|
||||||
|
names.add("-- Select Customer --");
|
||||||
|
for (CustomerDTO c : customerList)
|
||||||
|
names.add(c.getFirstName() + " " + c.getLastName());
|
||||||
|
spinnerCustomer.setAdapter(new ArrayAdapter<>(requireContext(),
|
||||||
|
android.R.layout.simple_spinner_item, names));
|
||||||
|
if (preselectedCustomerId != -1) {
|
||||||
|
for (int i = 0; i < customerList.size(); i++) {
|
||||||
|
if (customerList.get(i).getCustomerId().equals(preselectedCustomerId)) {
|
||||||
|
spinnerCustomer.setSelection(i + 1); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadStores() {
|
||||||
|
RetrofitClient.getStoreApi(requireContext()).getAllStores(0, 50)
|
||||||
|
.enqueue(new Callback<PageResponse<StoreDTO>>() {
|
||||||
|
public void onResponse(Call<PageResponse<StoreDTO>> c, Response<PageResponse<StoreDTO>> r) {
|
||||||
|
if (r.isSuccessful() && r.body() != null) {
|
||||||
|
storeList = r.body().getContent();
|
||||||
|
populateStoreSpinner();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void onFailure(Call<PageResponse<StoreDTO>> c, Throwable t) {
|
||||||
|
Log.e("APPT", "Store load failed: " + t.getMessage());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void populateStoreSpinner() {
|
||||||
|
List<String> names = new ArrayList<>();
|
||||||
|
names.add("-- Select Store --");
|
||||||
|
for (StoreDTO s : storeList) names.add(s.getStoreName());
|
||||||
|
spinnerStore.setAdapter(new ArrayAdapter<>(requireContext(),
|
||||||
|
android.R.layout.simple_spinner_item, names));
|
||||||
|
if (preselectedStoreId != -1) {
|
||||||
|
for (int i = 0; i < storeList.size(); i++) {
|
||||||
|
if (storeList.get(i).getStoreId().equals(preselectedStoreId)) {
|
||||||
|
spinnerStore.setSelection(i + 1); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadAllAppointments() {
|
||||||
|
RetrofitClient.getAppointmentApi(requireContext()).getAllAppointments(0, 500)
|
||||||
|
.enqueue(new Callback<PageResponse<AppointmentDTO>>() {
|
||||||
|
public void onResponse(Call<PageResponse<AppointmentDTO>> c, Response<PageResponse<AppointmentDTO>> r) {
|
||||||
|
if (r.isSuccessful() && r.body() != null)
|
||||||
|
allAppointments = r.body().getContent();
|
||||||
|
}
|
||||||
|
public void onFailure(Call<PageResponse<AppointmentDTO>> c, Throwable t) {}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private void handleArguments() {
|
private void handleArguments() {
|
||||||
if (getArguments() != null && getArguments().containsKey("appointmentId")) {
|
Bundle a = getArguments();
|
||||||
|
if (a != null && a.containsKey("appointmentId")) {
|
||||||
isEditing = true;
|
isEditing = true;
|
||||||
appointmentId = getArguments().getInt("appointmentId");
|
appointmentId = a.getLong("appointmentId");
|
||||||
position = getArguments().getInt("position");
|
preselectedPetId = a.getLong("petId", -1);
|
||||||
|
preselectedServiceId= a.getLong("serviceId", -1);
|
||||||
|
preselectedCustomerId = a.getLong("customerId", -1);
|
||||||
|
preselectedStoreId = a.getLong("storeId", -1);
|
||||||
|
|
||||||
tvMode.setText("Edit Appointment");
|
tvMode.setText("Edit Appointment");
|
||||||
tvAppointmentId.setText("ID: " + appointmentId);
|
tvAppointmentId.setText("ID: " + appointmentId);
|
||||||
etCustomerName.setText(getArguments().getString("customerName"));
|
tvAppointmentId.setVisibility(View.VISIBLE);
|
||||||
etPetName.setText(getArguments().getString("petName"));
|
etAppointmentDate.setText(a.getString("appointmentDate"));
|
||||||
etServiceType.setText(getArguments().getString("serviceType"));
|
btnDelete.setVisibility(View.VISIBLE);
|
||||||
etAppointmentDate.setText(getArguments().getString("appointmentDate"));
|
|
||||||
etAppointmentTime.setText(getArguments().getString("appointmentTime"));
|
// Pre-fill time spinners
|
||||||
String status = getArguments().getString("status");
|
String time = a.getString("appointmentTime", "09:00");
|
||||||
if ("Confirmed".equals(status)) spinnerStatus.setSelection(0);
|
if (time.length() > 5) time = time.substring(0, 5);
|
||||||
else if ("Pending".equals(status)) spinnerStatus.setSelection(1);
|
String[] parts = time.split(":");
|
||||||
else spinnerStatus.setSelection(2);
|
if (parts.length == 2) {
|
||||||
btnDeleteAppointment.setVisibility(View.VISIBLE);
|
int hour = Integer.parseInt(parts[0]);
|
||||||
|
int min = Integer.parseInt(parts[1]);
|
||||||
|
for (int i = 0; i < HOURS.length; i++)
|
||||||
|
if (HOURS[i] == hour) { spinnerHour.setSelection(i); break; }
|
||||||
|
for (int i = 0; i < MINUTES.length; i++)
|
||||||
|
if (MINUTES[i] == min) { spinnerMinute.setSelection(i); break; }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pre-fill status
|
||||||
|
String status = a.getString("appointmentStatus", "Booked");
|
||||||
|
for (int i = 0; i < STATUSES.length; i++)
|
||||||
|
if (STATUSES[i].equals(status)) { spinnerStatus.setSelection(i); break; }
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
isEditing = false;
|
|
||||||
tvMode.setText("Add Appointment");
|
tvMode.setText("Add Appointment");
|
||||||
|
btnDelete.setVisibility(View.GONE);
|
||||||
tvAppointmentId.setVisibility(View.GONE);
|
tvAppointmentId.setVisibility(View.GONE);
|
||||||
btnDeleteAppointment.setVisibility(View.GONE);
|
|
||||||
btnSaveAppointment.setText("Add");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initViews(View view) {
|
private void saveAppointment() {
|
||||||
tvMode = view.findViewById(R.id.tvApptMode);
|
if (spinnerCustomer.getSelectedItemPosition() == 0) {
|
||||||
tvAppointmentId = view.findViewById(R.id.tvAppointmentId);
|
Toast.makeText(getContext(), "Select a customer", Toast.LENGTH_SHORT).show(); return;
|
||||||
etCustomerName = view.findViewById(R.id.etCustomerName);
|
}
|
||||||
etPetName = view.findViewById(R.id.etApptPetName);
|
if (spinnerStore.getSelectedItemPosition() == 0) {
|
||||||
etServiceType = view.findViewById(R.id.etServiceType);
|
Toast.makeText(getContext(), "Select a store", Toast.LENGTH_SHORT).show(); return;
|
||||||
etAppointmentDate = view.findViewById(R.id.etAppointmentDate);
|
}
|
||||||
etAppointmentTime = view.findViewById(R.id.etAppointmentTime);
|
if (spinnerPet.getSelectedItemPosition() == 0) {
|
||||||
spinnerStatus = view.findViewById(R.id.spinnerAppointmentStatus);
|
Toast.makeText(getContext(), "Select a pet", Toast.LENGTH_SHORT).show(); return;
|
||||||
btnSaveAppointment = view.findViewById(R.id.btnSaveAppointment);
|
}
|
||||||
btnDeleteAppointment = view.findViewById(R.id.btnDeleteAppointment);
|
if (spinnerService.getSelectedItemPosition() == 0) {
|
||||||
btnBack = view.findViewById(R.id.btnApptBack);
|
Toast.makeText(getContext(), "Select a service", Toast.LENGTH_SHORT).show(); return;
|
||||||
|
}
|
||||||
|
String date = etAppointmentDate.getText().toString().trim();
|
||||||
|
if (date.isEmpty()) {
|
||||||
|
Toast.makeText(getContext(), "Select a date", Toast.LENGTH_SHORT).show(); return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomerDTO customer = customerList.get(spinnerCustomer.getSelectedItemPosition() - 1);
|
||||||
|
StoreDTO store = storeList.get(spinnerStore.getSelectedItemPosition() - 1);
|
||||||
|
PetDTO pet = petList.get(spinnerPet.getSelectedItemPosition() - 1);
|
||||||
|
ServiceDTO service = serviceList.get(spinnerService.getSelectedItemPosition() - 1);
|
||||||
|
|
||||||
|
String time = String.format("%02d:%02d",
|
||||||
|
HOURS[spinnerHour.getSelectedItemPosition()],
|
||||||
|
MINUTES[spinnerMinute.getSelectedItemPosition()]);
|
||||||
|
String status = STATUSES[spinnerStatus.getSelectedItemPosition()];
|
||||||
|
|
||||||
|
|
||||||
|
// Validate future date+time if status is Booked
|
||||||
|
if ("Booked".equalsIgnoreCase(status)) {
|
||||||
|
try {
|
||||||
|
String[] dateParts = date.split("-");
|
||||||
|
String[] timeParts = time.split(":");
|
||||||
|
Calendar selected = Calendar.getInstance();
|
||||||
|
selected.set(
|
||||||
|
Integer.parseInt(dateParts[0]),
|
||||||
|
Integer.parseInt(dateParts[1]) - 1,
|
||||||
|
Integer.parseInt(dateParts[2]),
|
||||||
|
Integer.parseInt(timeParts[0]),
|
||||||
|
Integer.parseInt(timeParts[1]),
|
||||||
|
0
|
||||||
|
);
|
||||||
|
if (selected.before(Calendar.getInstance())) {
|
||||||
|
showErrorDialog("Invalid Time",
|
||||||
|
"Booked appointments must be in the future. " +
|
||||||
|
"Please select a future date and time.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e("APPT_SAVE", "Date parse error: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build DTO with all required IDs
|
||||||
|
AppointmentDTO dto = new AppointmentDTO(
|
||||||
|
customer.getCustomerId(),
|
||||||
|
store.getStoreId(),
|
||||||
|
service.getServiceId(),
|
||||||
|
date,
|
||||||
|
time,
|
||||||
|
status,
|
||||||
|
Collections.singletonList(pet.getPetId())
|
||||||
|
);
|
||||||
|
|
||||||
|
Log.d("APPT_SAVE", "customerId=" + customer.getCustomerId()
|
||||||
|
+ " storeId=" + store.getStoreId()
|
||||||
|
+ " serviceId=" + service.getServiceId()
|
||||||
|
+ " petId=" + pet.getPetId()
|
||||||
|
+ " date=" + date + " time=" + time);
|
||||||
|
|
||||||
|
AppointmentApi api = RetrofitClient.getAppointmentApi(requireContext());
|
||||||
|
if (isEditing) {
|
||||||
|
api.updateAppointment(appointmentId, dto).enqueue(simpleCallback("Updated"));
|
||||||
|
} else {
|
||||||
|
api.createAppointment(dto).enqueue(simpleCallback("Saved"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupSpinner() {
|
private Callback<AppointmentDTO> simpleCallback(String msg) {
|
||||||
ArrayAdapter<String> adapter = new ArrayAdapter<String>(requireContext(),
|
return new Callback<>() {
|
||||||
android.R.layout.simple_spinner_item,
|
public void onResponse(Call<AppointmentDTO> c, Response<AppointmentDTO> r) {
|
||||||
new String[]{"Confirmed", "Pending", "Cancelled"}) {
|
Log.d("APPT_SAVE", "Response: " + r.code());
|
||||||
|
if (r.isSuccessful()) {
|
||||||
|
Toast.makeText(getContext(), msg, Toast.LENGTH_SHORT).show();
|
||||||
|
navigateBack();
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
String errorBody = r.errorBody().string();
|
||||||
|
Log.e("APPT_SAVE", "Error: " + errorBody);
|
||||||
|
|
||||||
//Override the getView method for the spinner to make the text color darker for more readability
|
// Show proper dialog based on error type
|
||||||
@NonNull
|
if (errorBody.toLowerCase().contains("future")) {
|
||||||
@Override
|
showErrorDialog("Invalid Date/Time",
|
||||||
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
|
"Booked appointments must be scheduled in the future. " +
|
||||||
View view = super.getView(position, convertView, parent);
|
"Please select a future date and time.");
|
||||||
((TextView) view).setTextColor(ContextCompat.getColor(requireContext(), R.color.text_dark));
|
//------------------------------------------
|
||||||
return view;
|
} else if (errorBody.toLowerCase().contains("not available") ||
|
||||||
|
errorBody.toLowerCase().contains("time is not available")) {
|
||||||
|
showNoAvailabilityDialog();
|
||||||
|
} else if (r.code() == 404) {
|
||||||
|
showErrorDialog("Not Found",
|
||||||
|
"The selected pet, customer or service was not found.");
|
||||||
|
} else if (r.code() == 403) {
|
||||||
|
showErrorDialog("Access Denied",
|
||||||
|
"You don't have permission to perform this action.");
|
||||||
|
} else if (r.code() == 400) {
|
||||||
|
showErrorDialog("Invalid Request", errorBody);
|
||||||
|
} else {
|
||||||
|
showErrorDialog("Error", "Something went wrong. Please try again.");
|
||||||
|
}
|
||||||
|
//-----------------------------
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e("APPT_SAVE", "Failed to read error body");
|
||||||
|
showErrorDialog("Error", "Something went wrong. Please try again.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onFailure(Call<AppointmentDTO> c, Throwable t) {
|
||||||
|
Log.e("APPT_SAVE", "Failure: " + t.getMessage());
|
||||||
|
Toast.makeText(getContext(), "Network error", Toast.LENGTH_SHORT).show();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
|
||||||
spinnerStatus.setAdapter(adapter);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
private void showNoAvailabilityDialog() {
|
||||||
|
new AlertDialog.Builder(requireContext())
|
||||||
|
.setTitle("No Availability")
|
||||||
|
.setMessage("This time slot is already booked for the selected service and store. Please choose a different time or date.")
|
||||||
|
.setPositiveButton("Change Time", (d, w) -> d.dismiss())
|
||||||
|
.setNegativeButton("Cancel Booking", (d, w) -> navigateBack())
|
||||||
|
.setCancelable(false)
|
||||||
|
.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showErrorDialog(String title, String message) {
|
||||||
|
new AlertDialog.Builder(requireContext())
|
||||||
|
.setTitle(title)
|
||||||
|
.setMessage(message)
|
||||||
|
.setPositiveButton("OK", null)
|
||||||
|
.show();
|
||||||
|
}
|
||||||
|
private void confirmDelete() {
|
||||||
|
new AlertDialog.Builder(requireContext())
|
||||||
|
.setTitle("Delete Appointment?")
|
||||||
|
.setPositiveButton("Yes", (d, w) ->
|
||||||
|
RetrofitClient.getAppointmentApi(requireContext())
|
||||||
|
.deleteAppointment(appointmentId)
|
||||||
|
.enqueue(new Callback<Void>() {
|
||||||
|
public void onResponse(Call<Void> c, Response<Void> r) { navigateBack(); }
|
||||||
|
public void onFailure(Call<Void> c, Throwable t) {
|
||||||
|
Toast.makeText(getContext(), "Delete failed", Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
.setNegativeButton("No", null).show();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void navigateBack() {
|
||||||
|
ListFragment lf = (ListFragment) getParentFragment();
|
||||||
|
if (lf != null) lf.getChildFragmentManager().popBackStack();
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user