fix photo loading issue on pets and products

This commit is contained in:
Alex
2026-04-04 21:21:25 -06:00
parent be79de7c82
commit 47bd755e72
5 changed files with 92 additions and 76 deletions

View File

@@ -107,7 +107,8 @@ public class PetAdapter extends RecyclerView.Adapter<PetAdapter.PetViewHolder> {
Glide.with(holder.itemView.getContext()) Glide.with(holder.itemView.getContext())
.load(loadTarget) .load(loadTarget)
.circleCrop() .circleCrop()
.diskCacheStrategy(DiskCacheStrategy.ALL) // Changed to ALL for better performance .skipMemoryCache(true)
.diskCacheStrategy(DiskCacheStrategy.NONE)
.placeholder(R.drawable.placeholder) .placeholder(R.drawable.placeholder)
.error(R.drawable.placeholder) .error(R.drawable.placeholder)
.into(holder.ivPetProfile); .into(holder.ivPetProfile);

View File

@@ -83,7 +83,8 @@ public class ProductAdapter extends RecyclerView.Adapter<ProductAdapter.ProductV
Glide.with(holder.itemView.getContext()) Glide.with(holder.itemView.getContext())
.load(loadTarget) .load(loadTarget)
.circleCrop() .circleCrop()
.diskCacheStrategy(DiskCacheStrategy.ALL) .skipMemoryCache(true)
.diskCacheStrategy(DiskCacheStrategy.NONE)
.placeholder(R.drawable.placeholder) .placeholder(R.drawable.placeholder)
.error(R.drawable.placeholder) .error(R.drawable.placeholder)
.into(holder.ivProductImage); .into(holder.ivProductImage);

View File

@@ -56,6 +56,8 @@ public class ProductDetailFragment extends Fragment {
private boolean isEditing = false; private boolean isEditing = false;
private long preselectedCategoryId = -1; private long preselectedCategoryId = -1;
private boolean hasImage = false; private boolean hasImage = false;
private boolean isImageChanged = false;
private boolean isImageRemoved = false;
private List<CategoryDTO> categoryList = new ArrayList<>(); private List<CategoryDTO> categoryList = new ArrayList<>();
private Uri photoUri; private Uri photoUri;
@@ -77,13 +79,12 @@ public class ProductDetailFragment extends Fragment {
result -> { result -> {
if (result.getResultCode() == Activity.RESULT_OK && result.getData() != null) { if (result.getResultCode() == Activity.RESULT_OK && result.getData() != null) {
Uri selectedImage = result.getData().getData(); Uri selectedImage = result.getData().getData();
if (isEditing) { // Update image view locally
uploadProductImage(selectedImage); Glide.with(this).load(selectedImage).into(ivProductImage);
} else { photoUri = selectedImage;
ivProductImage.setImageURI(selectedImage); hasImage = true;
photoUri = selectedImage; isImageChanged = true;
hasImage = true; isImageRemoved = false;
}
} }
} }
); );
@@ -91,12 +92,11 @@ public class ProductDetailFragment extends Fragment {
new ActivityResultContracts.TakePicture(), new ActivityResultContracts.TakePicture(),
success -> { success -> {
if (success) { if (success) {
if (isEditing) { // Update image view locally
uploadProductImage(photoUri); Glide.with(this).load(photoUri).into(ivProductImage);
} else { hasImage = true;
ivProductImage.setImageURI(photoUri); isImageChanged = true;
hasImage = true; isImageRemoved = false;
}
} }
} }
); );
@@ -167,31 +167,13 @@ public class ProductDetailFragment extends Fragment {
.show(); .show();
} }
// Helper function to remove the photo // Helper function to remove the photo locally
private void removePhoto() { private void removePhoto() {
if (isEditing) { photoUri = null;
productApi.deleteProductImage(prodId) hasImage = false;
.enqueue(new Callback<Void>() { isImageChanged = false;
@Override isImageRemoved = true;
public void onResponse(Call<Void> call, Response<Void> response) { Glide.with(this).load(R.drawable.placeholder2).into(ivProductImage);
if (response.isSuccessful()) {
Toast.makeText(getContext(), "Photo removed", Toast.LENGTH_SHORT).show();
ivProductImage.setImageResource(R.drawable.placeholder2);
hasImage = false;
} else {
Toast.makeText(getContext(), "Failed to remove photo", Toast.LENGTH_SHORT).show();
}
}
@Override
public void onFailure(Call<Void> call, Throwable t) {
Toast.makeText(getContext(), "Network error", Toast.LENGTH_SHORT).show();
}
});
} else {
photoUri = null;
hasImage = false;
ivProductImage.setImageResource(R.drawable.placeholder2);
}
} }
// Helper function to launch the camera // Helper function to launch the camera
@@ -201,6 +183,7 @@ public class ProductDetailFragment extends Fragment {
cameraLauncher.launch(photoUri); cameraLauncher.launch(photoUri);
} }
// Helper function to load categories from the backend for the spinner
private void loadCategories() { private void loadCategories() {
categoryApi.getAllCategories(0, 100) categoryApi.getAllCategories(0, 100)
.enqueue(new Callback<PageResponse<CategoryDTO>>() { .enqueue(new Callback<PageResponse<CategoryDTO>>() {
@@ -217,6 +200,7 @@ public class ProductDetailFragment extends Fragment {
}); });
} }
// Helper function to populate the category spinner
private void populateCategorySpinner() { private void populateCategorySpinner() {
List<String> names = new ArrayList<>(); List<String> names = new ArrayList<>();
names.add("-- Select Category --"); names.add("-- Select Category --");
@@ -270,17 +254,50 @@ public class ProductDetailFragment extends Fragment {
Glide.with(this) Glide.with(this)
.load(loadTarget) .load(loadTarget)
.diskCacheStrategy(DiskCacheStrategy.ALL) .skipMemoryCache(true)
.diskCacheStrategy(DiskCacheStrategy.NONE)
.placeholder(R.drawable.placeholder2) .placeholder(R.drawable.placeholder2)
.error(R.drawable.placeholder2) .error(R.drawable.placeholder2)
.into(ivProductImage); .into(ivProductImage);
} }
// Function to upload the product image by calling the backend // Function to check any changes to the image and perform the appropriate action
private void uploadProductImage(Uri uri) { // updating/adding photo, removing photo or no change
private void performPendingImageActions(String successMsg) {
if (isImageRemoved) {
//if the image is removed then delete the image
productApi.deleteProductImage(prodId).enqueue(new Callback<Void>() {
@Override
public void onResponse(Call<Void> call, Response<Void> response) {
Toast.makeText(getContext(), successMsg, Toast.LENGTH_SHORT).show();
navigateBack();
}
@Override
public void onFailure(Call<Void> call, Throwable t) {
Toast.makeText(getContext(), successMsg + " (but image removal failed)", Toast.LENGTH_SHORT).show();
navigateBack();
}
});
} else if (isImageChanged && photoUri != null) {
//if the image is changed then upload it
uploadProductImageAndNavigate(photoUri, successMsg);
} else {
//if no changes then navigate back
Toast.makeText(getContext(), successMsg, Toast.LENGTH_SHORT).show();
navigateBack();
}
}
// Helper function to upload the product image by calling the backend
// and then navigate back to the previous screen
private void uploadProductImageAndNavigate(Uri uri, String successMsg) {
try { try {
File file = getFileFromUri(uri); File file = getFileFromUri(uri);
if (file == null) return; if (file == null) {
Toast.makeText(getContext(), successMsg, Toast.LENGTH_SHORT).show();
navigateBack();
return;
}
RequestBody requestFile = RequestBody.create(file, MediaType.parse(requireContext().getContentResolver().getType(uri))); RequestBody requestFile = RequestBody.create(file, MediaType.parse(requireContext().getContentResolver().getType(uri)));
MultipartBody.Part body = MultipartBody.Part.createFormData("image", file.getName(), requestFile); MultipartBody.Part body = MultipartBody.Part.createFormData("image", file.getName(), requestFile);
@@ -290,20 +307,22 @@ public class ProductDetailFragment extends Fragment {
@Override @Override
public void onResponse(Call<Void> call, Response<Void> response) { public void onResponse(Call<Void> call, Response<Void> response) {
if (response.isSuccessful()) { if (response.isSuccessful()) {
Toast.makeText(getContext(), "Image uploaded", Toast.LENGTH_SHORT).show(); Toast.makeText(getContext(), successMsg, Toast.LENGTH_SHORT).show();
hasImage = true;
loadProductImage();
} else { } else {
Toast.makeText(getContext(), "Upload failed", Toast.LENGTH_SHORT).show(); Toast.makeText(getContext(), successMsg + " (but image upload failed)", Toast.LENGTH_SHORT).show();
} }
navigateBack();
} }
@Override @Override
public void onFailure(Call<Void> call, Throwable t) { public void onFailure(Call<Void> call, Throwable t) {
Toast.makeText(getContext(), "Network error", Toast.LENGTH_SHORT).show(); Toast.makeText(getContext(), successMsg + " (network error during upload)", Toast.LENGTH_SHORT).show();
navigateBack();
} }
}); });
} catch (Exception e) { } catch (Exception e) {
Log.e("ProductDetail", "Error uploading image", e); Log.e("ProductDetail", "Error uploading image", e);
Toast.makeText(getContext(), successMsg, Toast.LENGTH_SHORT).show();
navigateBack();
} }
} }
@@ -326,6 +345,7 @@ public class ProductDetailFragment extends Fragment {
} }
} }
// Function to save the product to the server
private void saveProduct() { private void saveProduct() {
String name = etProductName.getText().toString().trim(); String name = etProductName.getText().toString().trim();
String desc = etProductDesc.getText().toString().trim(); String desc = etProductDesc.getText().toString().trim();
@@ -352,19 +372,27 @@ public class ProductDetailFragment extends Fragment {
ProductDTO dto = new ProductDTO(name, category.getCategoryId(), desc, price); ProductDTO dto = new ProductDTO(name, category.getCategoryId(), desc, price);
if (isEditing) { if (isEditing) {
productApi.updateProduct(prodId, dto).enqueue(simpleCallback("Updated")); productApi.updateProduct(prodId, dto).enqueue(new Callback<ProductDTO>() {
@Override
public void onResponse(Call<ProductDTO> call, Response<ProductDTO> response) {
if (response.isSuccessful()) {
performPendingImageActions("Updated");
} else {
Toast.makeText(getContext(), "Error " + response.code(), Toast.LENGTH_SHORT).show();
}
}
@Override
public void onFailure(Call<ProductDTO> call, Throwable t) {
Toast.makeText(getContext(), "Network error", Toast.LENGTH_SHORT).show();
}
});
} else { } else {
productApi.createProduct(dto).enqueue(new Callback<ProductDTO>() { productApi.createProduct(dto).enqueue(new Callback<ProductDTO>() {
@Override @Override
public void onResponse(Call<ProductDTO> call, Response<ProductDTO> response) { public void onResponse(Call<ProductDTO> call, Response<ProductDTO> response) {
if (response.isSuccessful() && response.body() != null) { if (response.isSuccessful() && response.body() != null) {
long newId = response.body().getProdId(); prodId = response.body().getProdId();
if (photoUri != null) { performPendingImageActions("Saved");
prodId = newId;
uploadProductImage(photoUri);
}
Toast.makeText(getContext(), "Saved", Toast.LENGTH_SHORT).show();
navigateBack();
} else { } else {
Toast.makeText(getContext(), "Error saving", Toast.LENGTH_SHORT).show(); Toast.makeText(getContext(), "Error saving", Toast.LENGTH_SHORT).show();
} }
@@ -377,22 +405,7 @@ public class ProductDetailFragment extends Fragment {
} }
} }
private Callback<ProductDTO> simpleCallback(String msg) { // Function to delete the product from the server
return new Callback<>() {
public void onResponse(Call<ProductDTO> c, Response<ProductDTO> r) {
if (r.isSuccessful()) {
Toast.makeText(getContext(), msg, Toast.LENGTH_SHORT).show();
navigateBack();
} else {
Toast.makeText(getContext(), "Error " + r.code(), Toast.LENGTH_SHORT).show();
}
}
public void onFailure(Call<ProductDTO> c, Throwable t) {
Toast.makeText(getContext(), "Network error", Toast.LENGTH_SHORT).show();
}
};
}
private void confirmDelete() { private void confirmDelete() {
new AlertDialog.Builder(requireContext()) new AlertDialog.Builder(requireContext())
.setTitle("Delete Product?") .setTitle("Delete Product?")

View File

@@ -212,7 +212,8 @@ public class PetProfileFragment extends Fragment {
Glide.with(this) Glide.with(this)
.load(loadTarget) .load(loadTarget)
.diskCacheStrategy(DiskCacheStrategy.ALL) .skipMemoryCache(true)
.diskCacheStrategy(DiskCacheStrategy.NONE)
.placeholder(R.drawable.placeholder) .placeholder(R.drawable.placeholder)
.error(R.drawable.placeholder) .error(R.drawable.placeholder)
.listener(new com.bumptech.glide.request.RequestListener<android.graphics.drawable.Drawable>() { .listener(new com.bumptech.glide.request.RequestListener<android.graphics.drawable.Drawable>() {
@@ -311,4 +312,4 @@ public class PetProfileFragment extends Fragment {
photoUri = FileProvider.getUriForFile(requireContext(), requireContext().getPackageName() + ".fileprovider", photoFile); photoUri = FileProvider.getUriForFile(requireContext(), requireContext().getPackageName() + ".fileprovider", photoFile);
cameraLauncher.launch(photoUri); cameraLauncher.launch(photoUri);
} }
} }

View File

@@ -16,7 +16,7 @@
android:name="androidx.navigation.fragment.NavHostFragment" android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
app:defaultNavHost="false" app:defaultNavHost="true"
app:navGraph="@navigation/list_nav_graph" /> app:navGraph="@navigation/list_nav_graph" />
<View <View
@@ -252,4 +252,4 @@
</LinearLayout> </LinearLayout>
</androidx.drawerlayout.widget.DrawerLayout> </androidx.drawerlayout.widget.DrawerLayout>