merge final branch #338
@@ -20,6 +20,7 @@ import javax.inject.Inject;
|
||||
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel;
|
||||
|
||||
// ViewModel for the pet detail/create screen
|
||||
@HiltViewModel
|
||||
public class PetDetailViewModel extends ViewModel {
|
||||
private static final String STATUS_AVAILABLE = "Available";
|
||||
@@ -38,13 +39,13 @@ public class PetDetailViewModel extends ViewModel {
|
||||
private final MutableLiveData<Boolean> isLoading = new MutableLiveData<>(false);
|
||||
private final MutableLiveData<ViewState> viewState = new MutableLiveData<>(new ViewState());
|
||||
|
||||
private long petId = -1;
|
||||
private long petId = -1; // -1 means creating a new pet
|
||||
private Long selectedCustomerId = null;
|
||||
private Long selectedStoreId = null;
|
||||
private String selectedSpecies = null;
|
||||
private String selectedBreed = null;
|
||||
private boolean isOriginallyOwnedOrAdopted = false;
|
||||
private Long originalCustomerId = null;
|
||||
private boolean isOriginallyOwnedOrAdopted = false; // used to restrict staff edits
|
||||
private Long originalCustomerId = null; // used to detect owner changes
|
||||
|
||||
@Inject
|
||||
public PetDetailViewModel(PetRepository petRepository, CustomerRepository customerRepository, StoreRepository storeRepository) {
|
||||
@@ -53,6 +54,7 @@ public class PetDetailViewModel extends ViewModel {
|
||||
this.storeRepository = storeRepository;
|
||||
}
|
||||
|
||||
// Loads customers, stores, and species dropdowns needed for the form
|
||||
public void loadInitialFormData() {
|
||||
observeOnce(customerRepository.getCustomerDropdowns(), resource -> {
|
||||
if (resource != null && resource.status == Resource.Status.SUCCESS && resource.data != null) {
|
||||
@@ -78,26 +80,18 @@ public class PetDetailViewModel extends ViewModel {
|
||||
initMode(id != -1);
|
||||
}
|
||||
|
||||
public long getPetId() {
|
||||
return petId;
|
||||
}
|
||||
public long getPetId() { return petId; }
|
||||
|
||||
public boolean isEditing() {
|
||||
ViewState current = viewState.getValue();
|
||||
return current != null && current.isEditing;
|
||||
}
|
||||
|
||||
public boolean isOriginallyOwnedOrAdopted() {
|
||||
return isOriginallyOwnedOrAdopted;
|
||||
}
|
||||
public boolean isOriginallyOwnedOrAdopted() { return isOriginallyOwnedOrAdopted; }
|
||||
|
||||
public Long getOriginalCustomerId() {
|
||||
return originalCustomerId;
|
||||
}
|
||||
public Long getOriginalCustomerId() { return originalCustomerId; }
|
||||
|
||||
public LiveData<ViewState> getViewState() {
|
||||
return viewState;
|
||||
}
|
||||
public LiveData<ViewState> getViewState() { return viewState; }
|
||||
|
||||
public void onCustomerSelected(int position) {
|
||||
List<DropdownDTO> list = customerList.getValue();
|
||||
@@ -106,7 +100,6 @@ public class PetDetailViewModel extends ViewModel {
|
||||
} else {
|
||||
selectedCustomerId = null;
|
||||
}
|
||||
|
||||
updateViewState(state -> state.selectedCustomerId = selectedCustomerId);
|
||||
}
|
||||
|
||||
@@ -114,7 +107,7 @@ public class PetDetailViewModel extends ViewModel {
|
||||
List<DropdownDTO> list = speciesList.getValue();
|
||||
if (position > 0 && list != null && position <= list.size()) {
|
||||
selectedSpecies = list.get(position - 1).getLabel();
|
||||
loadBreeds(selectedSpecies);
|
||||
loadBreeds(selectedSpecies); // reload breeds when species changes
|
||||
} else {
|
||||
selectedSpecies = null;
|
||||
breedList.setValue(new ArrayList<>());
|
||||
@@ -150,17 +143,17 @@ public class PetDetailViewModel extends ViewModel {
|
||||
} else {
|
||||
selectedStoreId = null;
|
||||
}
|
||||
|
||||
updateViewState(state -> state.selectedStoreId = selectedStoreId);
|
||||
}
|
||||
|
||||
public void onStatusSelected(String status) {
|
||||
updateViewState(state -> {
|
||||
state.selectedStatus = normalizeStatus(status);
|
||||
applyStatusRules(state, true);
|
||||
applyStatusRules(state, true); // clear invalid selections when status changes
|
||||
});
|
||||
}
|
||||
|
||||
// Sets up initial ViewState based on whether we're editing or creating
|
||||
public void initMode(boolean isEditing) {
|
||||
updateViewState(state -> {
|
||||
state.isEditing = isEditing;
|
||||
@@ -177,6 +170,7 @@ public class PetDetailViewModel extends ViewModel {
|
||||
}
|
||||
|
||||
if (!isEditing) {
|
||||
// Reset all selections for a blank create form
|
||||
selectedCustomerId = null;
|
||||
selectedStoreId = null;
|
||||
selectedSpecies = null;
|
||||
@@ -202,6 +196,7 @@ public class PetDetailViewModel extends ViewModel {
|
||||
selectedStoreId = pet.getStoreId();
|
||||
selectedSpecies = pet.getPetSpecies();
|
||||
selectedBreed = pet.getPetBreed();
|
||||
// Track original status to restrict staff from editing owned/adopted pets
|
||||
isOriginallyOwnedOrAdopted = STATUS_OWNED.equalsIgnoreCase(pet.getPetStatus())
|
||||
|| STATUS_ADOPTED.equalsIgnoreCase(pet.getPetStatus());
|
||||
originalCustomerId = pet.getCustomerId();
|
||||
@@ -217,7 +212,7 @@ public class PetDetailViewModel extends ViewModel {
|
||||
state.selectedBreed = selectedBreed;
|
||||
state.selectedStatus = normalizeStatus(pet.getPetStatus());
|
||||
state.isBreedEnabled = !state.isEditing && (selectedSpecies != null);
|
||||
applyStatusRules(state, false);
|
||||
applyStatusRules(state, false); // don't clear selections when loading existing data
|
||||
});
|
||||
}
|
||||
|
||||
@@ -231,46 +226,26 @@ public class PetDetailViewModel extends ViewModel {
|
||||
petDTO.setPetId(petId);
|
||||
return petRepository.updatePet(petId, petDTO);
|
||||
}
|
||||
|
||||
return petRepository.createPet(petDTO);
|
||||
}
|
||||
|
||||
public LiveData<Resource<Void>> deletePet() {
|
||||
return petRepository.deletePet(petId);
|
||||
}
|
||||
public LiveData<Resource<Void>> deletePet() { return petRepository.deletePet(petId); }
|
||||
|
||||
public LiveData<Resource<Void>> uploadPetImage(okhttp3.MultipartBody.Part image) {
|
||||
return petRepository.uploadPetImage(petId, image);
|
||||
}
|
||||
|
||||
public LiveData<Resource<Void>> deletePetImage() {
|
||||
return petRepository.deletePetImage(petId);
|
||||
}
|
||||
public LiveData<Resource<Void>> deletePetImage() { return petRepository.deletePetImage(petId); }
|
||||
|
||||
public LiveData<List<DropdownDTO>> getCustomerList() {
|
||||
return customerList;
|
||||
}
|
||||
public LiveData<List<DropdownDTO>> getCustomerList() { return customerList; }
|
||||
public LiveData<List<DropdownDTO>> getStoreList() { return storeList; }
|
||||
public LiveData<List<DropdownDTO>> getSpeciesList() { return speciesList; }
|
||||
public LiveData<List<DropdownDTO>> getBreedList() { return breedList; }
|
||||
public LiveData<Boolean> getIsLoading() { return isLoading; }
|
||||
|
||||
public LiveData<List<DropdownDTO>> getStoreList() {
|
||||
return storeList;
|
||||
}
|
||||
|
||||
public LiveData<List<DropdownDTO>> getSpeciesList() {
|
||||
return speciesList;
|
||||
}
|
||||
|
||||
public LiveData<List<DropdownDTO>> getBreedList() {
|
||||
return breedList;
|
||||
}
|
||||
|
||||
public LiveData<Boolean> getIsLoading() {
|
||||
return isLoading;
|
||||
}
|
||||
|
||||
public void setLoading(boolean loading) {
|
||||
isLoading.setValue(loading);
|
||||
}
|
||||
public void setLoading(boolean loading) { isLoading.setValue(loading); }
|
||||
|
||||
// Enables/disables customer and store spinners based on the selected status
|
||||
private void applyStatusRules(ViewState state, boolean clearInvalidSelections) {
|
||||
if (STATUS_AVAILABLE.equalsIgnoreCase(state.selectedStatus)) {
|
||||
state.isCustomerEnabled = false;
|
||||
@@ -292,10 +267,12 @@ public class PetDetailViewModel extends ViewModel {
|
||||
return;
|
||||
}
|
||||
|
||||
// Adopted and Pending: both customer and store required
|
||||
state.isCustomerEnabled = true;
|
||||
state.isStoreEnabled = true;
|
||||
}
|
||||
|
||||
// Normalizes any status string to one of the four known constants
|
||||
private String normalizeStatus(String status) {
|
||||
if (status == null) return STATUS_AVAILABLE;
|
||||
String normalized = status.trim();
|
||||
@@ -305,6 +282,7 @@ public class PetDetailViewModel extends ViewModel {
|
||||
return STATUS_AVAILABLE;
|
||||
}
|
||||
|
||||
// Mutates the current ViewState and re-posts it to trigger UI updates
|
||||
private void updateViewState(Action<ViewState> action) {
|
||||
ViewState current = viewState.getValue();
|
||||
if (current != null) {
|
||||
@@ -317,6 +295,7 @@ public class PetDetailViewModel extends ViewModel {
|
||||
void run(T target);
|
||||
}
|
||||
|
||||
// Observes a LiveData exactly once, removing itself after the first non-loading result
|
||||
private <T> void observeOnce(LiveData<Resource<T>> liveData, Observer<Resource<T>> handler) {
|
||||
liveData.observeForever(new Observer<Resource<T>>() {
|
||||
@Override
|
||||
@@ -329,6 +308,7 @@ public class PetDetailViewModel extends ViewModel {
|
||||
});
|
||||
}
|
||||
|
||||
// Holds all UI state for the pet detail screen
|
||||
public static class ViewState {
|
||||
public boolean isEditing = false;
|
||||
public boolean isDeleteVisible = false;
|
||||
|
||||
Reference in New Issue
Block a user