From 47bd755e723c14c466764cb702d63ab3d0d0bde1 Mon Sep 17 00:00:00 2001 From: Alex <78383757+Lextical@users.noreply.github.com> Date: Sat, 4 Apr 2026 21:21:25 -0600 Subject: [PATCH] fix photo loading issue on pets and products --- .../petstoremobile/adapters/PetAdapter.java | 3 +- .../adapters/ProductAdapter.java | 3 +- .../ProductDetailFragment.java | 153 ++++++++++-------- .../PetProfileFragment.java | 5 +- .../app/src/main/res/layout/fragment_list.xml | 4 +- 5 files changed, 92 insertions(+), 76 deletions(-) diff --git a/android/app/src/main/java/com/example/petstoremobile/adapters/PetAdapter.java b/android/app/src/main/java/com/example/petstoremobile/adapters/PetAdapter.java index 1f1c5120..bec941f0 100644 --- a/android/app/src/main/java/com/example/petstoremobile/adapters/PetAdapter.java +++ b/android/app/src/main/java/com/example/petstoremobile/adapters/PetAdapter.java @@ -107,7 +107,8 @@ public class PetAdapter extends RecyclerView.Adapter { Glide.with(holder.itemView.getContext()) .load(loadTarget) .circleCrop() - .diskCacheStrategy(DiskCacheStrategy.ALL) // Changed to ALL for better performance + .skipMemoryCache(true) + .diskCacheStrategy(DiskCacheStrategy.NONE) .placeholder(R.drawable.placeholder) .error(R.drawable.placeholder) .into(holder.ivPetProfile); diff --git a/android/app/src/main/java/com/example/petstoremobile/adapters/ProductAdapter.java b/android/app/src/main/java/com/example/petstoremobile/adapters/ProductAdapter.java index 2363a682..4e7c5fea 100644 --- a/android/app/src/main/java/com/example/petstoremobile/adapters/ProductAdapter.java +++ b/android/app/src/main/java/com/example/petstoremobile/adapters/ProductAdapter.java @@ -83,7 +83,8 @@ public class ProductAdapter extends RecyclerView.Adapter categoryList = new ArrayList<>(); private Uri photoUri; @@ -77,13 +79,12 @@ public class ProductDetailFragment extends Fragment { result -> { if (result.getResultCode() == Activity.RESULT_OK && result.getData() != null) { Uri selectedImage = result.getData().getData(); - if (isEditing) { - uploadProductImage(selectedImage); - } else { - ivProductImage.setImageURI(selectedImage); - photoUri = selectedImage; - hasImage = true; - } + // Update image view locally + Glide.with(this).load(selectedImage).into(ivProductImage); + photoUri = selectedImage; + hasImage = true; + isImageChanged = true; + isImageRemoved = false; } } ); @@ -91,12 +92,11 @@ public class ProductDetailFragment extends Fragment { new ActivityResultContracts.TakePicture(), success -> { if (success) { - if (isEditing) { - uploadProductImage(photoUri); - } else { - ivProductImage.setImageURI(photoUri); - hasImage = true; - } + // Update image view locally + Glide.with(this).load(photoUri).into(ivProductImage); + hasImage = true; + isImageChanged = true; + isImageRemoved = false; } } ); @@ -167,31 +167,13 @@ public class ProductDetailFragment extends Fragment { .show(); } - // Helper function to remove the photo + // Helper function to remove the photo locally private void removePhoto() { - if (isEditing) { - productApi.deleteProductImage(prodId) - .enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - 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 call, Throwable t) { - Toast.makeText(getContext(), "Network error", Toast.LENGTH_SHORT).show(); - } - }); - } else { - photoUri = null; - hasImage = false; - ivProductImage.setImageResource(R.drawable.placeholder2); - } + photoUri = null; + hasImage = false; + isImageChanged = false; + isImageRemoved = true; + Glide.with(this).load(R.drawable.placeholder2).into(ivProductImage); } // Helper function to launch the camera @@ -201,6 +183,7 @@ public class ProductDetailFragment extends Fragment { cameraLauncher.launch(photoUri); } + // Helper function to load categories from the backend for the spinner private void loadCategories() { categoryApi.getAllCategories(0, 100) .enqueue(new Callback>() { @@ -217,6 +200,7 @@ public class ProductDetailFragment extends Fragment { }); } + // Helper function to populate the category spinner private void populateCategorySpinner() { List names = new ArrayList<>(); names.add("-- Select Category --"); @@ -270,17 +254,50 @@ public class ProductDetailFragment extends Fragment { Glide.with(this) .load(loadTarget) - .diskCacheStrategy(DiskCacheStrategy.ALL) + .skipMemoryCache(true) + .diskCacheStrategy(DiskCacheStrategy.NONE) .placeholder(R.drawable.placeholder2) .error(R.drawable.placeholder2) .into(ivProductImage); } - // Function to upload the product image by calling the backend - private void uploadProductImage(Uri uri) { + // Function to check any changes to the image and perform the appropriate action + // 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() { + @Override + public void onResponse(Call call, Response response) { + Toast.makeText(getContext(), successMsg, Toast.LENGTH_SHORT).show(); + navigateBack(); + } + @Override + public void onFailure(Call 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 { 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))); MultipartBody.Part body = MultipartBody.Part.createFormData("image", file.getName(), requestFile); @@ -290,20 +307,22 @@ public class ProductDetailFragment extends Fragment { @Override public void onResponse(Call call, Response response) { if (response.isSuccessful()) { - Toast.makeText(getContext(), "Image uploaded", Toast.LENGTH_SHORT).show(); - hasImage = true; - loadProductImage(); + Toast.makeText(getContext(), successMsg, Toast.LENGTH_SHORT).show(); } else { - Toast.makeText(getContext(), "Upload failed", Toast.LENGTH_SHORT).show(); + Toast.makeText(getContext(), successMsg + " (but image upload failed)", Toast.LENGTH_SHORT).show(); } + navigateBack(); } @Override public void onFailure(Call 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) { 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() { String name = etProductName.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); if (isEditing) { - productApi.updateProduct(prodId, dto).enqueue(simpleCallback("Updated")); + productApi.updateProduct(prodId, dto).enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + if (response.isSuccessful()) { + performPendingImageActions("Updated"); + } else { + Toast.makeText(getContext(), "Error " + response.code(), Toast.LENGTH_SHORT).show(); + } + } + @Override + public void onFailure(Call call, Throwable t) { + Toast.makeText(getContext(), "Network error", Toast.LENGTH_SHORT).show(); + } + }); } else { productApi.createProduct(dto).enqueue(new Callback() { @Override public void onResponse(Call call, Response response) { if (response.isSuccessful() && response.body() != null) { - long newId = response.body().getProdId(); - if (photoUri != null) { - prodId = newId; - uploadProductImage(photoUri); - } - Toast.makeText(getContext(), "Saved", Toast.LENGTH_SHORT).show(); - navigateBack(); + prodId = response.body().getProdId(); + performPendingImageActions("Saved"); } else { Toast.makeText(getContext(), "Error saving", Toast.LENGTH_SHORT).show(); } @@ -377,22 +405,7 @@ public class ProductDetailFragment extends Fragment { } } - private Callback simpleCallback(String msg) { - return new Callback<>() { - public void onResponse(Call c, Response 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 c, Throwable t) { - Toast.makeText(getContext(), "Network error", Toast.LENGTH_SHORT).show(); - } - }; - } - + // Function to delete the product from the server private void confirmDelete() { new AlertDialog.Builder(requireContext()) .setTitle("Delete Product?") diff --git a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/listprofilefragments/PetProfileFragment.java b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/listprofilefragments/PetProfileFragment.java index e8accaaf..6e6943d1 100644 --- a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/listprofilefragments/PetProfileFragment.java +++ b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/listprofilefragments/PetProfileFragment.java @@ -212,7 +212,8 @@ public class PetProfileFragment extends Fragment { Glide.with(this) .load(loadTarget) - .diskCacheStrategy(DiskCacheStrategy.ALL) + .skipMemoryCache(true) + .diskCacheStrategy(DiskCacheStrategy.NONE) .placeholder(R.drawable.placeholder) .error(R.drawable.placeholder) .listener(new com.bumptech.glide.request.RequestListener() { @@ -311,4 +312,4 @@ public class PetProfileFragment extends Fragment { photoUri = FileProvider.getUriForFile(requireContext(), requireContext().getPackageName() + ".fileprovider", photoFile); cameraLauncher.launch(photoUri); } -} \ No newline at end of file +} diff --git a/android/app/src/main/res/layout/fragment_list.xml b/android/app/src/main/res/layout/fragment_list.xml index 58d0bb2f..a55933b9 100644 --- a/android/app/src/main/res/layout/fragment_list.xml +++ b/android/app/src/main/res/layout/fragment_list.xml @@ -16,7 +16,7 @@ android:name="androidx.navigation.fragment.NavHostFragment" android:layout_width="match_parent" android:layout_height="match_parent" - app:defaultNavHost="false" + app:defaultNavHost="true" app:navGraph="@navigation/list_nav_graph" /> - \ No newline at end of file +