|
|
|
|
@@ -1,5 +1,6 @@
|
|
|
|
|
package com.example.petstoremobile.fragments.listfragments.detailfragments;
|
|
|
|
|
|
|
|
|
|
import android.net.Uri;
|
|
|
|
|
import android.os.Bundle;
|
|
|
|
|
|
|
|
|
|
import androidx.annotation.NonNull;
|
|
|
|
|
@@ -16,7 +17,10 @@ import android.widget.Spinner;
|
|
|
|
|
import android.widget.TextView;
|
|
|
|
|
import android.widget.Toast;
|
|
|
|
|
|
|
|
|
|
import com.bumptech.glide.Glide;
|
|
|
|
|
import com.bumptech.glide.load.engine.DiskCacheStrategy;
|
|
|
|
|
import com.example.petstoremobile.R;
|
|
|
|
|
import com.example.petstoremobile.api.PetApi;
|
|
|
|
|
import com.example.petstoremobile.api.auth.TokenManager;
|
|
|
|
|
import com.example.petstoremobile.databinding.FragmentPetDetailBinding;
|
|
|
|
|
import com.example.petstoremobile.dtos.DropdownDTO;
|
|
|
|
|
@@ -24,18 +28,26 @@ import com.example.petstoremobile.dtos.PetDTO;
|
|
|
|
|
import com.example.petstoremobile.utils.ActivityLogger;
|
|
|
|
|
import com.example.petstoremobile.utils.DateTimeUtils;
|
|
|
|
|
import com.example.petstoremobile.utils.DialogUtils;
|
|
|
|
|
import com.example.petstoremobile.utils.FileUtils;
|
|
|
|
|
import com.example.petstoremobile.utils.GlideUtils;
|
|
|
|
|
import com.example.petstoremobile.utils.ImagePickerHelper;
|
|
|
|
|
import com.example.petstoremobile.utils.InputValidator;
|
|
|
|
|
import com.example.petstoremobile.utils.Resource;
|
|
|
|
|
import com.example.petstoremobile.utils.SpinnerUtils;
|
|
|
|
|
import com.example.petstoremobile.utils.UIUtils;
|
|
|
|
|
import com.example.petstoremobile.viewmodels.PetDetailViewModel;
|
|
|
|
|
|
|
|
|
|
import java.io.File;
|
|
|
|
|
import java.util.List;
|
|
|
|
|
import java.util.Locale;
|
|
|
|
|
|
|
|
|
|
import javax.inject.Inject;
|
|
|
|
|
import javax.inject.Named;
|
|
|
|
|
|
|
|
|
|
import dagger.hilt.android.AndroidEntryPoint;
|
|
|
|
|
import okhttp3.MediaType;
|
|
|
|
|
import okhttp3.MultipartBody;
|
|
|
|
|
import okhttp3.RequestBody;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Fragment for displaying and editing pet details.
|
|
|
|
|
@@ -45,14 +57,45 @@ public class PetDetailFragment extends Fragment {
|
|
|
|
|
|
|
|
|
|
private FragmentPetDetailBinding binding;
|
|
|
|
|
private PetDetailViewModel viewModel;
|
|
|
|
|
private ImagePickerHelper imagePickerHelper;
|
|
|
|
|
private boolean isUpdatingUI = false;
|
|
|
|
|
|
|
|
|
|
private boolean hasImage = false;
|
|
|
|
|
private boolean isImageChanged = false;
|
|
|
|
|
private boolean isImageRemoved = false;
|
|
|
|
|
private Uri photoUri;
|
|
|
|
|
|
|
|
|
|
@Inject @Named("baseUrl") String baseUrl;
|
|
|
|
|
@Inject TokenManager tokenManager;
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void onCreate(Bundle savedInstanceState) {
|
|
|
|
|
super.onCreate(savedInstanceState);
|
|
|
|
|
viewModel = new ViewModelProvider(this).get(PetDetailViewModel.class);
|
|
|
|
|
|
|
|
|
|
imagePickerHelper = new ImagePickerHelper(this, "pet_photo.jpg", new ImagePickerHelper.ImagePickerListener() {
|
|
|
|
|
@Override
|
|
|
|
|
public void onImagePicked(Uri uri) {
|
|
|
|
|
photoUri = uri;
|
|
|
|
|
Glide.with(PetDetailFragment.this)
|
|
|
|
|
.load(uri)
|
|
|
|
|
.diskCacheStrategy(DiskCacheStrategy.NONE)
|
|
|
|
|
.skipMemoryCache(true)
|
|
|
|
|
.into(binding.ivPetImage);
|
|
|
|
|
hasImage = true;
|
|
|
|
|
isImageChanged = true;
|
|
|
|
|
isImageRemoved = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void onImageRemoved() {
|
|
|
|
|
photoUri = null;
|
|
|
|
|
hasImage = false;
|
|
|
|
|
isImageChanged = false;
|
|
|
|
|
isImageRemoved = true;
|
|
|
|
|
binding.ivPetImage.setImageResource(R.drawable.placeholder2);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
@@ -74,6 +117,7 @@ public class PetDetailFragment extends Fragment {
|
|
|
|
|
binding.btnBack.setOnClickListener(v -> navigateBack());
|
|
|
|
|
binding.btnSavePet.setOnClickListener(v -> savePet());
|
|
|
|
|
binding.btnDeletePet.setOnClickListener(v -> deletePet());
|
|
|
|
|
binding.ivPetImage.setOnClickListener(v -> imagePickerHelper.showImagePickerDialog("Select Pet Image", hasImage));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void observeViewModel() {
|
|
|
|
|
@@ -197,14 +241,18 @@ public class PetDetailFragment extends Fragment {
|
|
|
|
|
if (resource == null) return;
|
|
|
|
|
setLoading(resource.status == Resource.Status.LOADING);
|
|
|
|
|
if (resource.status == Resource.Status.SUCCESS) {
|
|
|
|
|
if (resource.data != null) {
|
|
|
|
|
viewModel.setPetId(resource.data.getPetId());
|
|
|
|
|
}
|
|
|
|
|
String msg;
|
|
|
|
|
if (viewModel.isEditing()) {
|
|
|
|
|
ActivityLogger.logChange(requireContext(), "Pet", "UPDATED", (int) viewModel.getPetId());
|
|
|
|
|
Toast.makeText(getContext(), "Pet updated successfully!", Toast.LENGTH_SHORT).show();
|
|
|
|
|
msg = "Pet updated successfully!";
|
|
|
|
|
} else {
|
|
|
|
|
ActivityLogger.log(requireContext(), "Added new Pet: " + name);
|
|
|
|
|
Toast.makeText(getContext(), "Pet added successfully!", Toast.LENGTH_SHORT).show();
|
|
|
|
|
msg = "Pet added successfully!";
|
|
|
|
|
}
|
|
|
|
|
navigateToPetList();
|
|
|
|
|
performPendingImageActions(msg);
|
|
|
|
|
} else if (resource.status == Resource.Status.ERROR) {
|
|
|
|
|
Toast.makeText(getContext(), "Error: " + resource.message, Toast.LENGTH_SHORT).show();
|
|
|
|
|
}
|
|
|
|
|
@@ -239,10 +287,75 @@ public class PetDetailFragment extends Fragment {
|
|
|
|
|
if (getArguments() != null && getArguments().containsKey("petId")) {
|
|
|
|
|
viewModel.setPetId(getArguments().getLong("petId"));
|
|
|
|
|
loadPetData();
|
|
|
|
|
loadPetImage();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
viewModel.setPetId(-1);
|
|
|
|
|
hasImage = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void loadPetImage() {
|
|
|
|
|
String imageUrl = baseUrl + String.format(Locale.US, PetApi.PET_IMAGE_PATH, viewModel.getPetId());
|
|
|
|
|
String token = tokenManager.getToken();
|
|
|
|
|
GlideUtils.loadImageWithToken(requireContext(), binding.ivPetImage, imageUrl, token, R.drawable.placeholder2, new GlideUtils.ImageLoadListener() {
|
|
|
|
|
@Override
|
|
|
|
|
public void onResourceReady() {
|
|
|
|
|
hasImage = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void onLoadFailed() {
|
|
|
|
|
hasImage = false;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void performPendingImageActions(String successMsg) {
|
|
|
|
|
if (isImageRemoved) {
|
|
|
|
|
viewModel.deletePetImage().observe(getViewLifecycleOwner(), resource -> {
|
|
|
|
|
if (resource == null) return;
|
|
|
|
|
setLoading(resource.status == Resource.Status.LOADING);
|
|
|
|
|
if (resource.status != Resource.Status.LOADING) {
|
|
|
|
|
if (resource.status == Resource.Status.SUCCESS) {
|
|
|
|
|
Toast.makeText(getContext(), successMsg, Toast.LENGTH_SHORT).show();
|
|
|
|
|
} else {
|
|
|
|
|
Toast.makeText(getContext(), successMsg + " (but image removal failed)", Toast.LENGTH_SHORT).show();
|
|
|
|
|
}
|
|
|
|
|
navigateToPetList();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
} else if (isImageChanged && photoUri != null) {
|
|
|
|
|
uploadPetImageAndNavigate(photoUri, successMsg);
|
|
|
|
|
} else {
|
|
|
|
|
Toast.makeText(getContext(), successMsg, Toast.LENGTH_SHORT).show();
|
|
|
|
|
navigateToPetList();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void uploadPetImageAndNavigate(Uri uri, String successMsg) {
|
|
|
|
|
File file = FileUtils.getFileFromUri(requireContext(), uri);
|
|
|
|
|
if (file == null) {
|
|
|
|
|
Toast.makeText(getContext(), successMsg, Toast.LENGTH_SHORT).show();
|
|
|
|
|
navigateToPetList();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RequestBody requestFile = RequestBody.create(file, MediaType.parse(requireContext().getContentResolver().getType(uri)));
|
|
|
|
|
MultipartBody.Part body = MultipartBody.Part.createFormData("image", file.getName(), requestFile);
|
|
|
|
|
|
|
|
|
|
viewModel.uploadPetImage(body).observe(getViewLifecycleOwner(), resource -> {
|
|
|
|
|
if (resource == null) return;
|
|
|
|
|
setLoading(resource.status == Resource.Status.LOADING);
|
|
|
|
|
if (resource.status != Resource.Status.LOADING) {
|
|
|
|
|
if (resource.status == Resource.Status.SUCCESS) {
|
|
|
|
|
Toast.makeText(getContext(), successMsg, Toast.LENGTH_SHORT).show();
|
|
|
|
|
} else {
|
|
|
|
|
Toast.makeText(getContext(), successMsg + " (but image upload failed)", Toast.LENGTH_SHORT).show();
|
|
|
|
|
}
|
|
|
|
|
navigateToPetList();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void loadPetData() {
|
|
|
|
|
|