fix photo loading issue on pets and products

This commit is contained in:
Alex
2026-04-04 21:21:25 -06:00
parent f59624f9c3
commit 44877cd4ad
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())
.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);

View File

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

View File

@@ -56,6 +56,8 @@ public class ProductDetailFragment extends Fragment {
private boolean isEditing = false;
private long preselectedCategoryId = -1;
private boolean hasImage = false;
private boolean isImageChanged = false;
private boolean isImageRemoved = false;
private List<CategoryDTO> 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<Void>() {
@Override
public void onResponse(Call<Void> call, Response<Void> 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<Void> 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<PageResponse<CategoryDTO>>() {
@@ -217,6 +200,7 @@ public class ProductDetailFragment extends Fragment {
});
}
// Helper function to populate the category spinner
private void populateCategorySpinner() {
List<String> 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<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 {
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<Void> call, Response<Void> 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<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) {
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<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 {
productApi.createProduct(dto).enqueue(new Callback<ProductDTO>() {
@Override
public void onResponse(Call<ProductDTO> call, Response<ProductDTO> 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<ProductDTO> simpleCallback(String msg) {
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();
}
};
}
// Function to delete the product from the server
private void confirmDelete() {
new AlertDialog.Builder(requireContext())
.setTitle("Delete Product?")

View File

@@ -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<android.graphics.drawable.Drawable>() {
@@ -311,4 +312,4 @@ public class PetProfileFragment extends Fragment {
photoUri = FileProvider.getUriForFile(requireContext(), requireContext().getPackageName() + ".fileprovider", photoFile);
cameraLauncher.launch(photoUri);
}
}
}

View File

@@ -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" />
<View
@@ -252,4 +252,4 @@
</LinearLayout>
</androidx.drawerlayout.widget.DrawerLayout>
</androidx.drawerlayout.widget.DrawerLayout>