changed petDetailFragment to support new backend
This commit is contained in:
@@ -1,6 +1,9 @@
|
|||||||
package com.example.petstoremobile.dtos;
|
package com.example.petstoremobile.dtos;
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
public class CustomerDTO {
|
public class CustomerDTO {
|
||||||
|
@SerializedName("id")
|
||||||
private Long customerId;
|
private Long customerId;
|
||||||
private String firstName;
|
private String firstName;
|
||||||
private String lastName;
|
private String lastName;
|
||||||
@@ -12,18 +15,34 @@ public class CustomerDTO {
|
|||||||
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 getFullName() {
|
public String getFullName() {
|
||||||
return firstName + " " + lastName;
|
return firstName + " " + lastName;
|
||||||
}
|
}
|
||||||
@@ -32,7 +51,15 @@ public class CustomerDTO {
|
|||||||
return createdAt;
|
return createdAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setCreatedAt(String createdAt) {
|
||||||
|
this.createdAt = createdAt;
|
||||||
|
}
|
||||||
|
|
||||||
public String getUpdatedAt() {
|
public String getUpdatedAt() {
|
||||||
return updatedAt;
|
return updatedAt;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
public void setUpdatedAt(String updatedAt) {
|
||||||
|
this.updatedAt = updatedAt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -11,18 +11,27 @@ import androidx.navigation.fragment.NavHostFragment;
|
|||||||
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.AdapterView;
|
||||||
|
import android.widget.Spinner;
|
||||||
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.example.petstoremobile.R;
|
import com.example.petstoremobile.R;
|
||||||
import com.example.petstoremobile.databinding.FragmentPetDetailBinding;
|
import com.example.petstoremobile.databinding.FragmentPetDetailBinding;
|
||||||
|
import com.example.petstoremobile.dtos.CustomerDTO;
|
||||||
import com.example.petstoremobile.dtos.PetDTO;
|
import com.example.petstoremobile.dtos.PetDTO;
|
||||||
|
import com.example.petstoremobile.dtos.StoreDTO;
|
||||||
import com.example.petstoremobile.utils.ActivityLogger;
|
import com.example.petstoremobile.utils.ActivityLogger;
|
||||||
import com.example.petstoremobile.utils.DialogUtils;
|
import com.example.petstoremobile.utils.DialogUtils;
|
||||||
import com.example.petstoremobile.utils.InputValidator;
|
import com.example.petstoremobile.utils.InputValidator;
|
||||||
import com.example.petstoremobile.utils.Resource;
|
import com.example.petstoremobile.utils.Resource;
|
||||||
import com.example.petstoremobile.utils.SpinnerUtils;
|
import com.example.petstoremobile.utils.SpinnerUtils;
|
||||||
|
import com.example.petstoremobile.viewmodels.CustomerViewModel;
|
||||||
import com.example.petstoremobile.viewmodels.PetViewModel;
|
import com.example.petstoremobile.viewmodels.PetViewModel;
|
||||||
|
import com.example.petstoremobile.viewmodels.StoreViewModel;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
import dagger.hilt.android.AndroidEntryPoint;
|
import dagger.hilt.android.AndroidEntryPoint;
|
||||||
@@ -38,11 +47,19 @@ public class PetDetailFragment extends Fragment {
|
|||||||
private boolean isEditing = false;
|
private boolean isEditing = false;
|
||||||
|
|
||||||
private PetViewModel viewModel;
|
private PetViewModel viewModel;
|
||||||
|
private CustomerViewModel customerViewModel;
|
||||||
|
private StoreViewModel storeViewModel;
|
||||||
|
private List<CustomerDTO> customerList = new ArrayList<>();
|
||||||
|
private List<StoreDTO> storeList = new ArrayList<>();
|
||||||
|
private Long selectedCustomerId = null;
|
||||||
|
private Long selectedStoreId = null;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
viewModel = new ViewModelProvider(this).get(PetViewModel.class);
|
viewModel = new ViewModelProvider(this).get(PetViewModel.class);
|
||||||
|
customerViewModel = new ViewModelProvider(this).get(CustomerViewModel.class);
|
||||||
|
storeViewModel = new ViewModelProvider(this).get(StoreViewModel.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -57,6 +74,8 @@ public class PetDetailFragment extends Fragment {
|
|||||||
super.onViewCreated(view, savedInstanceState);
|
super.onViewCreated(view, savedInstanceState);
|
||||||
|
|
||||||
setupSpinner();
|
setupSpinner();
|
||||||
|
loadCustomers();
|
||||||
|
loadStores();
|
||||||
handleArguments();
|
handleArguments();
|
||||||
|
|
||||||
//set button click listeners
|
//set button click listeners
|
||||||
@@ -90,6 +109,36 @@ public class PetDetailFragment extends Fragment {
|
|||||||
double price = Double.parseDouble(binding.etPetPrice.getText().toString().trim());
|
double price = Double.parseDouble(binding.etPetPrice.getText().toString().trim());
|
||||||
String status = binding.spinnerPetStatus.getSelectedItem().toString();
|
String status = binding.spinnerPetStatus.getSelectedItem().toString();
|
||||||
|
|
||||||
|
// Get selected customer
|
||||||
|
Long customerId = null;
|
||||||
|
int customerPos = binding.spinnerCustomer.getSelectedItemPosition();
|
||||||
|
if (customerPos > 0) { // 0 means no customer for pet
|
||||||
|
customerId = customerList.get(customerPos - 1).getCustomerId();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get selected store
|
||||||
|
Long storeId = null;
|
||||||
|
int storePos = binding.spinnerStore.getSelectedItemPosition();
|
||||||
|
if (storePos > 0) {
|
||||||
|
storeId = storeList.get(storePos - 1).getStoreId();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validation: If status is Available, a store must be selected
|
||||||
|
if ("Available".equalsIgnoreCase(status)) {
|
||||||
|
if (!InputValidator.isSpinnerSelected(binding.spinnerStore, "Store")) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validation: If status is Owned, an owner must be selected
|
||||||
|
if ("Owned".equalsIgnoreCase(status)) {
|
||||||
|
if (!InputValidator.isSpinnerSelected(binding.spinnerCustomer, "Owner")) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validation: If status is Adopted, an owner and store must be selected
|
||||||
|
if ("Adopted".equalsIgnoreCase(status)) {
|
||||||
|
if (!InputValidator.isSpinnerSelected(binding.spinnerCustomer, "Owner")) return;
|
||||||
|
if (!InputValidator.isSpinnerSelected(binding.spinnerStore, "Store")) return;
|
||||||
|
}
|
||||||
|
|
||||||
//create a pet object to send to the API
|
//create a pet object to send to the API
|
||||||
PetDTO petDTO = new PetDTO();
|
PetDTO petDTO = new PetDTO();
|
||||||
petDTO.setPetName(name);
|
petDTO.setPetName(name);
|
||||||
@@ -98,6 +147,8 @@ public class PetDetailFragment extends Fragment {
|
|||||||
petDTO.setPetAge(age);
|
petDTO.setPetAge(age);
|
||||||
petDTO.setPetPrice(price);
|
petDTO.setPetPrice(price);
|
||||||
petDTO.setPetStatus(status);
|
petDTO.setPetStatus(status);
|
||||||
|
petDTO.setCustomerId(customerId);
|
||||||
|
petDTO.setStoreId(storeId);
|
||||||
|
|
||||||
//check if the pet is being edited or added
|
//check if the pet is being edited or added
|
||||||
if (isEditing) {
|
if (isEditing) {
|
||||||
@@ -197,17 +248,118 @@ public class PetDetailFragment extends Fragment {
|
|||||||
binding.etPetPrice.setText(String.format(Locale.getDefault(), "%.2f", p.getPetPrice()));
|
binding.etPetPrice.setText(String.format(Locale.getDefault(), "%.2f", p.getPetPrice()));
|
||||||
}
|
}
|
||||||
SpinnerUtils.setSelectionByValue(binding.spinnerPetStatus, p.getPetStatus());
|
SpinnerUtils.setSelectionByValue(binding.spinnerPetStatus, p.getPetStatus());
|
||||||
|
|
||||||
|
selectedCustomerId = p.getCustomerId();
|
||||||
|
updateCustomerSpinnerSelection();
|
||||||
|
|
||||||
|
selectedStoreId = p.getStoreId();
|
||||||
|
updateStoreSpinnerSelection();
|
||||||
} else if (resource.status == Resource.Status.ERROR) {
|
} else if (resource.status == Resource.Status.ERROR) {
|
||||||
Toast.makeText(getContext(), "Failed to load pet: " + resource.message, Toast.LENGTH_SHORT).show();
|
Toast.makeText(getContext(), "Failed to load pet: " + resource.message, Toast.LENGTH_SHORT).show();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches the list of customers and populates the spinner.
|
||||||
|
*/
|
||||||
|
private void loadCustomers() {
|
||||||
|
customerViewModel.getAllCustomers(0, 1000).observe(getViewLifecycleOwner(), resource -> {
|
||||||
|
if (resource != null && resource.status == Resource.Status.SUCCESS && resource.data != null) {
|
||||||
|
customerList = resource.data.getContent();
|
||||||
|
updateCustomerSpinnerSelection();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches the list of stores and populates the spinner.
|
||||||
|
*/
|
||||||
|
private void loadStores() {
|
||||||
|
storeViewModel.getAllStores(0, 1000).observe(getViewLifecycleOwner(), resource -> {
|
||||||
|
if (resource != null && resource.status == Resource.Status.SUCCESS && resource.data != null) {
|
||||||
|
storeList = resource.data.getContent();
|
||||||
|
updateStoreSpinnerSelection();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the customer spinner with the current list and sets the selection if needed.
|
||||||
|
*/
|
||||||
|
private void updateCustomerSpinnerSelection() {
|
||||||
|
SpinnerUtils.populateSpinner(
|
||||||
|
requireContext(),
|
||||||
|
binding.spinnerCustomer,
|
||||||
|
customerList,
|
||||||
|
CustomerDTO::getFullName,
|
||||||
|
"No Owner",
|
||||||
|
selectedCustomerId,
|
||||||
|
CustomerDTO::getCustomerId
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the store spinner with the current list and sets the selection if needed.
|
||||||
|
*/
|
||||||
|
private void updateStoreSpinnerSelection() {
|
||||||
|
SpinnerUtils.populateSpinner(
|
||||||
|
requireContext(),
|
||||||
|
binding.spinnerStore,
|
||||||
|
storeList,
|
||||||
|
StoreDTO::getStoreName,
|
||||||
|
"None",
|
||||||
|
selectedStoreId,
|
||||||
|
StoreDTO::getStoreId
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes the spinner for pet status selection.
|
* Initializes the spinner for pet status selection.
|
||||||
*/
|
*/
|
||||||
private void setupSpinner() {
|
private void setupSpinner() {
|
||||||
SpinnerUtils.setupStringSpinner(requireContext(), binding.spinnerPetStatus,
|
SpinnerUtils.setupStringSpinner(requireContext(), binding.spinnerPetStatus,
|
||||||
new String[]{"Available", "Adopted"});
|
new String[]{"Available", "Adopted", "Owned"});
|
||||||
|
|
||||||
|
binding.spinnerPetStatus.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
|
||||||
|
@Override
|
||||||
|
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
|
||||||
|
String status = parent.getItemAtPosition(position).toString();
|
||||||
|
|
||||||
|
// Clear any existing error icons when status changes
|
||||||
|
clearSpinnerError(binding.spinnerCustomer);
|
||||||
|
clearSpinnerError(binding.spinnerStore);
|
||||||
|
|
||||||
|
//Disable the customer spinner if the status is "Available"
|
||||||
|
if ("Available".equalsIgnoreCase(status)) {
|
||||||
|
binding.spinnerCustomer.setSelection(0);
|
||||||
|
binding.spinnerCustomer.setEnabled(false);
|
||||||
|
} else {
|
||||||
|
binding.spinnerCustomer.setEnabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Disable the store spinner if the status is "Owned"
|
||||||
|
if ("Owned".equalsIgnoreCase(status)) {
|
||||||
|
binding.spinnerStore.setSelection(0);
|
||||||
|
binding.spinnerStore.setEnabled(false);
|
||||||
|
} else {
|
||||||
|
binding.spinnerStore.setEnabled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onNothingSelected(AdapterView<?> parent) {
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears error messages from a Spinner's selected view.
|
||||||
|
*/
|
||||||
|
private void clearSpinnerError(Spinner spinner) {
|
||||||
|
View selectedView = spinner.getSelectedView();
|
||||||
|
if (selectedView instanceof TextView) {
|
||||||
|
((TextView) selectedView).setError(null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -130,6 +130,13 @@ public class PetProfileFragment extends Fragment {
|
|||||||
} else {
|
} else {
|
||||||
binding.tvPetPrice.setText("$0.00");
|
binding.tvPetPrice.setText("$0.00");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Display owner name if available, otherwise show No Owner
|
||||||
|
if (pet.getCustomerName() != null && !pet.getCustomerName().isEmpty()) {
|
||||||
|
binding.tvPetOwner.setText(pet.getCustomerName());
|
||||||
|
} else {
|
||||||
|
binding.tvPetOwner.setText("No Owner");
|
||||||
|
}
|
||||||
} else if (resource.status == Resource.Status.ERROR) {
|
} else if (resource.status == Resource.Status.ERROR) {
|
||||||
Toast.makeText(getContext(), "Failed to load pet data: " + resource.message, Toast.LENGTH_SHORT).show();
|
Toast.makeText(getContext(), "Failed to load pet data: " + resource.message, Toast.LENGTH_SHORT).show();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
package com.example.petstoremobile.utils;
|
package com.example.petstoremobile.utils;
|
||||||
|
|
||||||
|
import android.view.View;
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
|
import android.widget.Spinner;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
public class InputValidator {
|
public class InputValidator {
|
||||||
|
|
||||||
@@ -94,4 +97,21 @@ public class InputValidator {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a selection has been made in a Spinner.
|
||||||
|
* Assumes position 0 is a placeholder like "None" or "Select".
|
||||||
|
*/
|
||||||
|
public static boolean isSpinnerSelected(Spinner spinner, String fieldName) {
|
||||||
|
if (spinner.getSelectedItemPosition() <= 0) {
|
||||||
|
View selectedView = spinner.getSelectedView();
|
||||||
|
if (selectedView instanceof TextView) {
|
||||||
|
TextView tv = (TextView) selectedView;
|
||||||
|
tv.setError(fieldName + " is required");
|
||||||
|
spinner.requestFocus();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import com.example.petstoremobile.adapters.BlackTextArrayAdapter;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -36,7 +37,8 @@ public class SpinnerUtils {
|
|||||||
if (preselectedId != null && preselectedId != -1) {
|
if (preselectedId != null && preselectedId != -1) {
|
||||||
int offset = (defaultText != null) ? 1 : 0;
|
int offset = (defaultText != null) ? 1 : 0;
|
||||||
for (int i = 0; i < data.size(); i++) {
|
for (int i = 0; i < data.size(); i++) {
|
||||||
if (idExtractor.apply(data.get(i)).equals(preselectedId)) {
|
Long currentId = idExtractor.apply(data.get(i));
|
||||||
|
if (Objects.equals(currentId, preselectedId)) {
|
||||||
spinner.setSelection(i + offset);
|
spinner.setSelection(i + offset);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -161,6 +161,34 @@
|
|||||||
<Spinner
|
<Spinner
|
||||||
android:id="@+id/spinnerPetStatus"
|
android:id="@+id/spinnerPetStatus"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="16dp"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Owner"
|
||||||
|
android:textColor="@color/text_dark"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:layout_marginBottom="4dp"/>
|
||||||
|
|
||||||
|
<Spinner
|
||||||
|
android:id="@+id/spinnerCustomer"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="16dp"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Store"
|
||||||
|
android:textColor="@color/text_dark"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:layout_marginBottom="4dp"/>
|
||||||
|
|
||||||
|
<Spinner
|
||||||
|
android:id="@+id/spinnerStore"
|
||||||
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"/>
|
android:layout_height="wrap_content"/>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|||||||
@@ -221,6 +221,35 @@
|
|||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:gravity="center"
|
||||||
|
android:background="@color/white"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="OWNER"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:textColor="#888888"
|
||||||
|
android:textAllCaps="true"
|
||||||
|
android:layout_marginBottom="4dp"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvPetOwner"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="No Owner"
|
||||||
|
android:textSize="20sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:textColor="@color/text_dark"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
@@ -241,4 +270,4 @@
|
|||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|||||||
Reference in New Issue
Block a user