From 38a024226484d7d4c099eaaa7e07396b062f8733 Mon Sep 17 00:00:00 2001 From: Alex <78383757+Lextical@users.noreply.github.com> Date: Sun, 5 Apr 2026 21:27:32 -0600 Subject: [PATCH] Refactored more of the project to MVVM and created helper class RetrofitUtil to reduce redundent code --- .../activities/HomeActivity.java | 11 +- .../fragments/ChatFragment.java | 146 ++++------- .../fragments/ProfileFragment.java | 129 +++------- .../AdoptionDetailFragment.java | 133 +++++------ .../AppointmentDetailFragment.java | 226 +++++++----------- .../InventoryDetailFragment.java | 129 ++++------ .../detailfragments/PetDetailFragment.java | 94 +++----- .../ProductSupplierDetailFragment.java | 132 +++++----- .../ServiceDetailFragment.java | 95 +++----- .../SupplierDetailFragment.java | 96 +++----- .../PetProfileFragment.java | 50 +--- .../repositories/AdoptionRepository.java | 91 +------ .../repositories/AppointmentRepository.java | 91 +------ .../repositories/AuthRepository.java | 105 ++------ .../repositories/CategoryRepository.java | 23 +- .../repositories/CustomerRepository.java | 50 ++++ .../repositories/InventoryRepository.java | 116 ++------- .../repositories/PetRepository.java | 129 ++-------- .../repositories/ProductRepository.java | 124 ++-------- .../ProductSupplierRepository.java | 74 +----- .../repositories/PurchaseOrderRepository.java | 38 +-- .../repositories/ServiceRepository.java | 91 +------ .../repositories/StoreRepository.java | 37 +++ .../repositories/SupplierRepository.java | 99 ++------ .../services/ChatNotificationService.java | 74 ++---- .../petstoremobile/utils/RetrofitUtils.java | 74 ++++++ .../viewmodels/CustomerViewModel.java | 37 +++ .../viewmodels/StoreViewModel.java | 30 +++ 28 files changed, 855 insertions(+), 1669 deletions(-) create mode 100644 android/app/src/main/java/com/example/petstoremobile/repositories/CustomerRepository.java create mode 100644 android/app/src/main/java/com/example/petstoremobile/repositories/StoreRepository.java create mode 100644 android/app/src/main/java/com/example/petstoremobile/utils/RetrofitUtils.java create mode 100644 android/app/src/main/java/com/example/petstoremobile/viewmodels/CustomerViewModel.java create mode 100644 android/app/src/main/java/com/example/petstoremobile/viewmodels/StoreViewModel.java diff --git a/android/app/src/main/java/com/example/petstoremobile/activities/HomeActivity.java b/android/app/src/main/java/com/example/petstoremobile/activities/HomeActivity.java index 947b98e1..d9e41f96 100644 --- a/android/app/src/main/java/com/example/petstoremobile/activities/HomeActivity.java +++ b/android/app/src/main/java/com/example/petstoremobile/activities/HomeActivity.java @@ -80,6 +80,7 @@ public class HomeActivity extends AppCompatActivity { @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); + setIntent(intent); // Set the new intent so fragments can access updated extras handleIntent(intent); } @@ -88,13 +89,9 @@ public class HomeActivity extends AppCompatActivity { */ private void handleIntent(Intent intent) { if (intent != null && "chat".equals(intent.getStringExtra("navigate_to"))) { - Bundle args = new Bundle(); - if (intent.hasExtra("conversation_id")) { - args.putLong("conversation_id", intent.getLongExtra("conversation_id", -1)); - } - // Use NavController to navigate - if (navController != null) { - navController.navigate(R.id.nav_chat, args); + if (bottomNav != null) { + // Navigate by selecting the bottom nav item. + bottomNav.setSelectedItemId(R.id.nav_chat); } } } diff --git a/android/app/src/main/java/com/example/petstoremobile/fragments/ChatFragment.java b/android/app/src/main/java/com/example/petstoremobile/fragments/ChatFragment.java index 8ceed48f..25f4a7f1 100644 --- a/android/app/src/main/java/com/example/petstoremobile/fragments/ChatFragment.java +++ b/android/app/src/main/java/com/example/petstoremobile/fragments/ChatFragment.java @@ -34,6 +34,7 @@ import com.example.petstoremobile.dtos.SendMessageRequest; import com.example.petstoremobile.models.Chat; import com.example.petstoremobile.models.Message; import com.example.petstoremobile.services.ChatNotificationService; +import com.example.petstoremobile.utils.RetrofitUtils; import com.example.petstoremobile.websocket.StompChatManager; import java.util.*; @@ -202,6 +203,10 @@ public class ChatFragment extends Fragment implements ChatAdapter.OnChatClickLis if (getArguments() != null && getArguments().containsKey("conversation_id")) { activeConversationId = getArguments().getLong("conversation_id"); + } else if (getActivity() != null && getActivity().getIntent().hasExtra("conversation_id")) { + activeConversationId = getActivity().getIntent().getLongExtra("conversation_id", -1); + getActivity().getIntent().removeExtra("conversation_id"); + getActivity().getIntent().removeExtra("navigate_to"); } loadCustomers(); @@ -211,74 +216,51 @@ public class ChatFragment extends Fragment implements ChatAdapter.OnChatClickLis * Fetches a list of customers from the API to display customer names for the chat list. */ private void loadCustomers() { - customerApi.getAllCustomers(0, 100).enqueue(new Callback>() { - @Override - public void onResponse(@NonNull Call> call, - @NonNull Response> response) { - if (response.isSuccessful() && response.body() != null) { - for (CustomerDTO c : response.body().getContent()) { - customerNames.put(c.getCustomerId(), c.getFullName()); - } - } - loadConversations(); + customerApi.getAllCustomers(0, 100).enqueue(RetrofitUtils.createSilentCallback(TAG, result -> { + for (CustomerDTO c : result.getContent()) { + customerNames.put(c.getCustomerId(), c.getFullName()); } - - @Override - public void onFailure(@NonNull Call> call, - @NonNull Throwable t) { - loadConversations(); - } - }); + loadConversations(); + })); } /** * Retrieves all conversations for the current user and populates the chat drawer. */ private void loadConversations() { - chatApi.getAllConversations().enqueue(new Callback>() { - @Override - public void onResponse(@NonNull Call> call, - @NonNull Response> response) { - if (response.isSuccessful() && response.body() != null) { - chatList.clear(); - List loaded = response.body().stream() - .map(dto -> { - String name = customerNames.getOrDefault( - dto.getCustomerId(), "Customer #" + dto.getCustomerId()); - return new Chat(String.valueOf(dto.getId()), - name, dto.getLastMessage(), - dto.getCustomerId(), dto.getStaffId()); - }) - .collect(Collectors.toList()); - chatList.addAll(loaded); - chatAdapter.notifyDataSetChanged(); - - if (activeConversationId != null) { - setConversationActive(true); - // Update title to customer name of active conversation - for (Chat chat : chatList) { - if (chat.getChatId().equals(String.valueOf(activeConversationId))) { - tvChatTitle.setText(chat.getCustomerName()); - break; - } - } - if (stompChatManager != null) { - stompChatManager.subscribeToConversation(activeConversationId); - } - loadMessageHistory(activeConversationId); - } else { - messageList.clear(); - messageAdapter.notifyDataSetChanged(); - setConversationActive(false); + chatApi.getAllConversations().enqueue(RetrofitUtils.createSilentCallback(TAG, result -> { + chatList.clear(); + List loaded = result.stream() + .map(dto -> { + String name = customerNames.getOrDefault( + dto.getCustomerId(), "Customer #" + dto.getCustomerId()); + return new Chat(String.valueOf(dto.getId()), + name, dto.getLastMessage(), + dto.getCustomerId(), dto.getStaffId()); + }) + .collect(Collectors.toList()); + chatList.addAll(loaded); + chatAdapter.notifyDataSetChanged(); + + if (activeConversationId != null) { + setConversationActive(true); + // Update title to customer name of active conversation + for (Chat chat : chatList) { + if (chat.getChatId().equals(String.valueOf(activeConversationId))) { + tvChatTitle.setText(chat.getCustomerName()); + break; } } + if (stompChatManager != null) { + stompChatManager.subscribeToConversation(activeConversationId); + } + loadMessageHistory(activeConversationId); + } else { + messageList.clear(); + messageAdapter.notifyDataSetChanged(); + setConversationActive(false); } - @Override - public void onFailure(@NonNull Call> call, - @NonNull Throwable t) { - Log.e(TAG, "Error loading conversations", t); - } - }); + })); } /** @@ -302,25 +284,14 @@ public class ChatFragment extends Fragment implements ChatAdapter.OnChatClickLis * Fetches the full message history for a specific conversation from the API. */ private void loadMessageHistory(Long conversationId) { - messageApi.getMessages(conversationId).enqueue(new Callback>() { - @Override - public void onResponse(@NonNull Call> call, - @NonNull Response> response) { - if (response.isSuccessful() && response.body() != null) { - messageList.clear(); - for (MessageDTO dto : response.body()) { - messageList.add(dtoToModel(dto)); - } - messageAdapter.notifyDataSetChanged(); - scrollToBottom(); - } + messageApi.getMessages(conversationId).enqueue(RetrofitUtils.createSilentCallback(TAG, result -> { + messageList.clear(); + for (MessageDTO dto : result) { + messageList.add(dtoToModel(dto)); } - @Override - public void onFailure(@NonNull Call> call, - @NonNull Throwable t) { - Log.e(TAG, "Error loading messages", t); - } - }); + messageAdapter.notifyDataSetChanged(); + scrollToBottom(); + })); } /** @@ -339,23 +310,12 @@ public class ChatFragment extends Fragment implements ChatAdapter.OnChatClickLis //calls api to send the message messageApi.sendMessage(activeConversationId, new SendMessageRequest(text)) - .enqueue(new Callback() { - @Override - public void onResponse(@NonNull Call call, - @NonNull Response response) { - if (response.isSuccessful() && response.body() != null) { - messageList.add(dtoToModel(response.body())); - messageAdapter.notifyItemInserted(messageList.size() - 1); - scrollToBottom(); - loadConversations(); - } - } - @Override - public void onFailure(@NonNull Call call, - @NonNull Throwable t) { - Log.e(TAG, "Send failed", t); - } - }); + .enqueue(RetrofitUtils.createSilentCallback(TAG, result -> { + messageList.add(dtoToModel(result)); + messageAdapter.notifyItemInserted(messageList.size() - 1); + scrollToBottom(); + loadConversations(); + })); } /** diff --git a/android/app/src/main/java/com/example/petstoremobile/fragments/ProfileFragment.java b/android/app/src/main/java/com/example/petstoremobile/fragments/ProfileFragment.java index b4f15e69..bcc8a0d8 100644 --- a/android/app/src/main/java/com/example/petstoremobile/fragments/ProfileFragment.java +++ b/android/app/src/main/java/com/example/petstoremobile/fragments/ProfileFragment.java @@ -27,6 +27,7 @@ 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.RetrofitUtils; import com.example.petstoremobile.utils.UIUtils; import java.io.File; @@ -189,47 +190,31 @@ public class ProfileFragment extends Fragment { * Fetches current user profile data from the API and then updates the UI. */ private void loadProfileData() { - authApi.getMe().enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - //if the response is successful and the body is not null then set the user to the view - if (response.isSuccessful() && response.body() != null) { - currentUser = response.body(); + authApi.getMe().enqueue(RetrofitUtils.createCallback(requireContext(), "PROFILE", null, result -> { + currentUser = result; - //set the user data to the view - tvProfileName.setText(currentUser.getFullName()); - tvProfileEmail.setText(currentUser.getEmail()); - tvProfilePhone.setText(currentUser.getPhone()); - tvProfileRole.setText(currentUser.getRole()); + //set the user data to the view + tvProfileName.setText(currentUser.getFullName()); + tvProfileEmail.setText(currentUser.getEmail()); + tvProfilePhone.setText(currentUser.getPhone()); + tvProfileRole.setText(currentUser.getRole()); - // get the avatar endpoint to load profile image and the token for authorization - String avatarUrl = baseUrl + AuthApi.AVATAR_FILE_PATH; - String token = tokenManager.getToken(); + // get the avatar endpoint to load profile image and the token for authorization + String avatarUrl = baseUrl + AuthApi.AVATAR_FILE_PATH; + String token = tokenManager.getToken(); - GlideUtils.loadImageWithToken(requireContext(), imgProfile, avatarUrl, token, R.drawable.placeholder, new GlideUtils.ImageLoadListener() { - @Override - public void onResourceReady() { - hasImage = true; - } - - @Override - public void onLoadFailed() { - hasImage = false; - } - }); + GlideUtils.loadImageWithToken(requireContext(), imgProfile, avatarUrl, token, R.drawable.placeholder, new GlideUtils.ImageLoadListener() { + @Override + public void onResourceReady() { + hasImage = true; } - else { - Log.e("onResponse: ", response.message()); - ErrorUtils.showErrorMessage(getContext(), response, "Failed to load profile"); - } - } - @Override - public void onFailure(Call call, Throwable t) { - Log.e("PROFILE", "onFailure: " + t.getMessage()); - Toast.makeText(getContext(), "Network error: could not load profile", Toast.LENGTH_SHORT).show(); - } - }); + @Override + public void onLoadFailed() { + hasImage = false; + } + }); + })); } /** @@ -245,25 +230,11 @@ public class ProfileFragment extends Fragment { MultipartBody.Part body = MultipartBody.Part.createFormData("avatar", file.getName(), requestFile); //Call the backend to upload the avatar - authApi.uploadAvatar(body).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful() && response.body() != null) { - currentUser = response.body(); - Toast.makeText(requireContext(), "Avatar updated successfully", Toast.LENGTH_SHORT).show(); - // Reload image after successful upload - loadProfileData(); - } else { - ErrorUtils.showErrorMessage(getContext(), response, "Failed to upload avatar"); - } - } - - @Override - public void onFailure(Call call, Throwable t) { - Log.e("UPLOAD_AVATAR", "Failure: " + t.getMessage()); - Toast.makeText(requireContext(), "Network error", Toast.LENGTH_SHORT).show(); - } - }); + authApi.uploadAvatar(body).enqueue(RetrofitUtils.createCallback(requireContext(), "UPLOAD_AVATAR", "Avatar updated successfully", result -> { + currentUser = result; + // Reload image after successful upload + loadProfileData(); + })); } catch (Exception e) { Log.e("UPLOAD_AVATAR", "Error: " + e.getMessage()); } @@ -273,24 +244,10 @@ public class ProfileFragment extends Fragment { * Sends a request to the API to delete the current user's avatar image. */ private void deleteAvatar() { - authApi.deleteAvatar().enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful()) { - Toast.makeText(requireContext(), "Avatar removed successfully", Toast.LENGTH_SHORT).show(); - hasImage = false; - imgProfile.setImageResource(R.drawable.placeholder); - } else { - ErrorUtils.showErrorMessage(getContext(), response, "Failed to remove avatar"); - } - } - - @Override - public void onFailure(Call call, Throwable t) { - Log.e("DELETE_AVATAR", "Failure: " + t.getMessage()); - Toast.makeText(requireContext(), "Network error", Toast.LENGTH_SHORT).show(); - } - }); + authApi.deleteAvatar().enqueue(RetrofitUtils.createCallback(requireContext(), "DELETE_AVATAR", "Avatar removed successfully", result -> { + hasImage = false; + imgProfile.setImageResource(R.drawable.placeholder); + })); } /** @@ -300,25 +257,11 @@ public class ProfileFragment extends Fragment { Map updates = new HashMap<>(); updates.put(fieldName, value); - authApi.updateMe(updates).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful() && response.body() != null) { - currentUser = response.body(); - // Update the view with the new data from backend - tvProfileEmail.setText(currentUser.getEmail()); - tvProfilePhone.setText(currentUser.getPhone()); - Toast.makeText(requireContext(), "Profile updated successfully", Toast.LENGTH_SHORT).show(); - } else { - ErrorUtils.showErrorMessage(getContext(), response, "Failed to update profile"); - } - } - - @Override - public void onFailure(Call call, Throwable t) { - Log.e("UPDATE_PROFILE", "Failure: " + t.getMessage()); - Toast.makeText(requireContext(), "Network error", Toast.LENGTH_SHORT).show(); - } - }); + authApi.updateMe(updates).enqueue(RetrofitUtils.createCallback(requireContext(), "UPDATE_PROFILE", "Profile updated successfully", result -> { + currentUser = result; + // Update the view with the new data from backend + tvProfileEmail.setText(currentUser.getEmail()); + tvProfilePhone.setText(currentUser.getPhone()); + })); } } diff --git a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/AdoptionDetailFragment.java b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/AdoptionDetailFragment.java index 61bed9f7..2aa140bf 100644 --- a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/AdoptionDetailFragment.java +++ b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/AdoptionDetailFragment.java @@ -7,21 +7,21 @@ import android.view.*; import android.widget.*; import androidx.annotation.NonNull; import androidx.fragment.app.Fragment; +import androidx.lifecycle.ViewModelProvider; import androidx.navigation.fragment.NavHostFragment; import com.example.petstoremobile.R; -import com.example.petstoremobile.api.*; import com.example.petstoremobile.dtos.*; import com.example.petstoremobile.utils.DialogUtils; -import com.example.petstoremobile.utils.ErrorUtils; +import com.example.petstoremobile.utils.Resource; import com.example.petstoremobile.utils.SpinnerUtils; +import com.example.petstoremobile.viewmodels.AdoptionViewModel; +import com.example.petstoremobile.viewmodels.CustomerViewModel; +import com.example.petstoremobile.viewmodels.PetViewModel; import java.util.*; -import javax.inject.Inject; - import dagger.hilt.android.AndroidEntryPoint; -import retrofit2.*; /** * Fragment for displaying and editing adoption request details. @@ -44,9 +44,17 @@ public class AdoptionDetailFragment extends Fragment { private final String[] STATUSES = {"Pending", "Approved", "Rejected"}; - @Inject AdoptionApi adoptionApi; - @Inject PetApi petApi; - @Inject CustomerApi customerApi; + private AdoptionViewModel adoptionViewModel; + private PetViewModel petViewModel; + private CustomerViewModel customerViewModel; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + adoptionViewModel = new ViewModelProvider(this).get(AdoptionViewModel.class); + petViewModel = new ViewModelProvider(this).get(PetViewModel.class); + customerViewModel = new ViewModelProvider(this).get(CustomerViewModel.class); + } @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, @@ -113,43 +121,29 @@ public class AdoptionDetailFragment extends Fragment { * Loads the list of pets from the API. */ private void loadPets() { - petApi.getAllPets(0, 200) - .enqueue(new Callback>() { - public void onResponse(Call> c, - Response> r) { - if (r.isSuccessful() && r.body() != null) { - petList = r.body().getContent(); - SpinnerUtils.populateSpinner(requireContext(), spinnerPet, petList, - PetDTO::getPetName, "-- Select Pet --", - preselectedPetId, PetDTO::getPetId); - } - } - public void onFailure(Call> c, Throwable t) { - Log.e("ADOPTION", "Pet load failed: " + t.getMessage()); - } - }); + petViewModel.getAllPets(0, 200).observe(getViewLifecycleOwner(), resource -> { + if (resource.status == Resource.Status.SUCCESS && resource.data != null) { + petList = resource.data.getContent(); + SpinnerUtils.populateSpinner(requireContext(), spinnerPet, petList, + PetDTO::getPetName, "-- Select Pet --", + preselectedPetId, PetDTO::getPetId); + } + }); } /** * Loads the list of customers from the API. */ private void loadCustomers() { - customerApi.getAllCustomers(0, 200) - .enqueue(new Callback>() { - public void onResponse(Call> c, - Response> r) { - if (r.isSuccessful() && r.body() != null) { - customerList = r.body().getContent(); - SpinnerUtils.populateSpinner(requireContext(), spinnerCustomer, customerList, - item -> item.getFirstName() + " " + item.getLastName(), - "-- Select Customer --", - preselectedCustomerId, CustomerDTO::getCustomerId); - } - } - public void onFailure(Call> c, Throwable t) { - Log.e("ADOPTION", "Customer load failed: " + t.getMessage()); - } - }); + customerViewModel.getAllCustomers(0, 200).observe(getViewLifecycleOwner(), resource -> { + if (resource.status == Resource.Status.SUCCESS && resource.data != null) { + customerList = resource.data.getContent(); + SpinnerUtils.populateSpinner(requireContext(), spinnerCustomer, customerList, + item -> item.getFirstName() + " " + item.getLastName(), + "-- Select Customer --", + preselectedCustomerId, CustomerDTO::getCustomerId); + } + }); } /** @@ -204,51 +198,40 @@ public class AdoptionDetailFragment extends Fragment { status ); - Log.d("ADOPTION_SAVE", "petId=" + pet.getPetId() - + " customerId=" + customer.getCustomerId() - + " date=" + date + " status=" + status); - if (isEditing) { - adoptionApi.updateAdoption(adoptionId, dto).enqueue(simpleCallback("Updated")); - } else { - adoptionApi.createAdoption(dto).enqueue(simpleCallback("Saved")); - } - } - - /** - * callback for adoption save/update operations. - */ - private Callback simpleCallback(String msg) { - return new Callback<>() { - public void onResponse(Call c, Response r) { - Log.d("ADOPTION_SAVE", "Response: " + r.code()); - if (r.isSuccessful()) { - Toast.makeText(getContext(), msg, Toast.LENGTH_SHORT).show(); + adoptionViewModel.updateAdoption(adoptionId, dto).observe(getViewLifecycleOwner(), resource -> { + if (resource.status == Resource.Status.SUCCESS) { + Toast.makeText(getContext(), "Updated", Toast.LENGTH_SHORT).show(); navigateBack(); - } else { - ErrorUtils.showErrorMessage(getContext(), r, "Error " + r.code()); + } else if (resource.status == Resource.Status.ERROR) { + Toast.makeText(getContext(), "Error: " + resource.message, Toast.LENGTH_SHORT).show(); } - } - public void onFailure(Call c, Throwable t) { - Log.e("ADOPTION_SAVE", "Failure: " + t.getMessage()); - Toast.makeText(getContext(), "Network error", Toast.LENGTH_SHORT).show(); - } - }; + }); + } else { + adoptionViewModel.createAdoption(dto).observe(getViewLifecycleOwner(), resource -> { + if (resource.status == Resource.Status.SUCCESS) { + Toast.makeText(getContext(), "Saved", Toast.LENGTH_SHORT).show(); + navigateBack(); + } else if (resource.status == Resource.Status.ERROR) { + Toast.makeText(getContext(), "Error: " + resource.message, Toast.LENGTH_SHORT).show(); + } + }); + } } /** * Shows a confirmation dialog before deleting an adoption request. */ private void confirmDelete() { - DialogUtils.showDeleteConfirmDialog(requireContext(), "Adoption", () -> - adoptionApi.deleteAdoption(adoptionId) - .enqueue(new Callback() { - public void onResponse(Call c, Response r) { navigateBack(); } - public void onFailure(Call c, Throwable t) { - Toast.makeText(getContext(), "Delete failed", - Toast.LENGTH_SHORT).show(); - } - })); + DialogUtils.showDeleteConfirmDialog(requireContext(), "Adoption", () -> + adoptionViewModel.deleteAdoption(adoptionId).observe(getViewLifecycleOwner(), resource -> { + if (resource.status == Resource.Status.SUCCESS) { + Toast.makeText(getContext(), "Deleted", Toast.LENGTH_SHORT).show(); + navigateBack(); + } else if (resource.status == Resource.Status.ERROR) { + Toast.makeText(getContext(), "Delete failed: " + resource.message, Toast.LENGTH_SHORT).show(); + } + })); } /** diff --git a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/AppointmentDetailFragment.java b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/AppointmentDetailFragment.java index 4f933788..f137bdfd 100644 --- a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/AppointmentDetailFragment.java +++ b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/AppointmentDetailFragment.java @@ -7,21 +7,23 @@ import android.view.*; import android.widget.*; import androidx.annotation.NonNull; import androidx.fragment.app.Fragment; +import androidx.lifecycle.ViewModelProvider; import androidx.navigation.fragment.NavHostFragment; import com.example.petstoremobile.R; -import com.example.petstoremobile.api.*; import com.example.petstoremobile.dtos.*; import com.example.petstoremobile.utils.DialogUtils; -import com.example.petstoremobile.utils.ErrorUtils; +import com.example.petstoremobile.utils.Resource; import com.example.petstoremobile.utils.SpinnerUtils; +import com.example.petstoremobile.viewmodels.AppointmentViewModel; +import com.example.petstoremobile.viewmodels.CustomerViewModel; +import com.example.petstoremobile.viewmodels.PetViewModel; +import com.example.petstoremobile.viewmodels.ServiceViewModel; +import com.example.petstoremobile.viewmodels.StoreViewModel; import java.util.*; -import javax.inject.Inject; - import dagger.hilt.android.AndroidEntryPoint; -import retrofit2.*; /** * Fragment for displaying and editing appointment details. @@ -46,17 +48,26 @@ public class AppointmentDetailFragment extends Fragment { private List serviceList = new ArrayList<>(); private List customerList = new ArrayList<>(); private List storeList = new ArrayList<>(); - private List allAppointments = new ArrayList<>(); private final Integer[] HOURS = {9,10,11,12,13,14,15,16,17}; private final Integer[] MINUTES = {0,15,30,45}; private final String[] STATUSES = {"Booked","Completed","Cancelled"}; - @Inject AppointmentApi appointmentApi; - @Inject PetApi petApi; - @Inject ServiceApi serviceApi; - @Inject CustomerApi customerApi; - @Inject StoreApi storeApi; + private AppointmentViewModel appointmentViewModel; + private PetViewModel petViewModel; + private ServiceViewModel serviceViewModel; + private StoreViewModel storeViewModel; + private CustomerViewModel customerViewModel; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + appointmentViewModel = new ViewModelProvider(this).get(AppointmentViewModel.class); + petViewModel = new ViewModelProvider(this).get(PetViewModel.class); + serviceViewModel = new ViewModelProvider(this).get(ServiceViewModel.class); + storeViewModel = new ViewModelProvider(this).get(StoreViewModel.class); + customerViewModel = new ViewModelProvider(this).get(CustomerViewModel.class); + } @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -129,102 +140,63 @@ public class AppointmentDetailFragment extends Fragment { loadServices(); loadCustomers(); loadStores(); - loadAllAppointments(); } /** - * Loads the list of pets from the API. + * Loads the list of pets from the ViewModel. */ private void loadPets() { - petApi.getAllPets(0, 200) - .enqueue(new Callback>() { - public void onResponse(Call> c, Response> r) { - if (r.isSuccessful() && r.body() != null) { - petList = r.body().getContent(); - SpinnerUtils.populateSpinner(requireContext(), spinnerPet, petList, - PetDTO::getPetName, "-- Select Pet --", - preselectedPetId, PetDTO::getPetId); - } - } - public void onFailure(Call> c, Throwable t) { - Log.e("APPT", "Pet load failed: " + t.getMessage()); - } - }); + petViewModel.getAllPets(0, 200).observe(getViewLifecycleOwner(), resource -> { + if (resource.status == Resource.Status.SUCCESS && resource.data != null) { + petList = resource.data.getContent(); + SpinnerUtils.populateSpinner(requireContext(), spinnerPet, petList, + PetDTO::getPetName, "-- Select Pet --", + preselectedPetId, PetDTO::getPetId); + } + }); } /** * Loads the list of services from the API. */ private void loadServices() { - serviceApi.getAllServices(0, 200) - .enqueue(new Callback>() { - public void onResponse(Call> c, Response> r) { - if (r.isSuccessful() && r.body() != null) { - serviceList = r.body().getContent(); - SpinnerUtils.populateSpinner(requireContext(), spinnerService, serviceList, - ServiceDTO::getServiceName, "-- Select Service --", - preselectedServiceId, ServiceDTO::getServiceId); - } - } - public void onFailure(Call> c, Throwable t) { - Log.e("APPT", "Service load failed: " + t.getMessage()); - } - }); + serviceViewModel.getAllServices(0, 200).observe(getViewLifecycleOwner(), resource -> { + if (resource.status == Resource.Status.SUCCESS && resource.data != null) { + serviceList = resource.data.getContent(); + SpinnerUtils.populateSpinner(requireContext(), spinnerService, serviceList, + ServiceDTO::getServiceName, "-- Select Service --", + preselectedServiceId, ServiceDTO::getServiceId); + } + }); } /** * Loads the list of customers from the API. */ private void loadCustomers() { - customerApi.getAllCustomers(0, 200) - .enqueue(new Callback>() { - public void onResponse(Call> c, Response> r) { - if (r.isSuccessful() && r.body() != null) { - customerList = r.body().getContent(); - SpinnerUtils.populateSpinner(requireContext(), spinnerCustomer, customerList, - item -> item.getFirstName() + " " + item.getLastName(), - "-- Select Customer --", - preselectedCustomerId, CustomerDTO::getCustomerId); - } - } - public void onFailure(Call> c, Throwable t) { - Log.e("APPT", "Customer load failed: " + t.getMessage()); - } - }); + customerViewModel.getAllCustomers(0, 200).observe(getViewLifecycleOwner(), resource -> { + if (resource.status == Resource.Status.SUCCESS && resource.data != null) { + customerList = resource.data.getContent(); + SpinnerUtils.populateSpinner(requireContext(), spinnerCustomer, customerList, + item -> item.getFirstName() + " " + item.getLastName(), + "-- Select Customer --", + preselectedCustomerId, CustomerDTO::getCustomerId); + } + }); } /** * Loads the list of stores from the API. */ private void loadStores() { - storeApi.getAllStores(0, 50) - .enqueue(new Callback>() { - public void onResponse(Call> c, Response> r) { - if (r.isSuccessful() && r.body() != null) { - storeList = r.body().getContent(); - SpinnerUtils.populateSpinner(requireContext(), spinnerStore, storeList, - StoreDTO::getStoreName, "-- Select Store --", - preselectedStoreId, StoreDTO::getStoreId); - } - } - public void onFailure(Call> c, Throwable t) { - Log.e("APPT", "Store load failed: " + t.getMessage()); - } - }); - } - - /** - * Loads all appointments from the API. - */ - private void loadAllAppointments() { - appointmentApi.getAllAppointments(0, 500) - .enqueue(new Callback>() { - public void onResponse(Call> c, Response> r) { - if (r.isSuccessful() && r.body() != null) - allAppointments = r.body().getContent(); - } - public void onFailure(Call> c, Throwable t) {} - }); + storeViewModel.getAllStores(0, 50).observe(getViewLifecycleOwner(), resource -> { + if (resource.status == Resource.Status.SUCCESS && resource.data != null) { + storeList = resource.data.getContent(); + SpinnerUtils.populateSpinner(requireContext(), spinnerStore, storeList, + StoreDTO::getStoreName, "-- Select Store --", + preselectedStoreId, StoreDTO::getStoreId); + } + }); } /** @@ -337,57 +309,36 @@ public class AppointmentDetailFragment extends Fragment { Collections.singletonList(pet.getPetId()) ); - Log.d("APPT_SAVE", "customerId=" + customer.getCustomerId() - + " storeId=" + store.getStoreId() - + " serviceId=" + service.getServiceId() - + " petId=" + pet.getPetId() - + " date=" + date + " time=" + time); + androidx.lifecycle.Observer> observer = resource -> { + if (resource.status == Resource.Status.SUCCESS) { + Toast.makeText(getContext(), isEditing ? "Updated" : "Saved", Toast.LENGTH_SHORT).show(); + navigateBack(); + } else if (resource.status == Resource.Status.ERROR) { + handleSaveError(resource.message); + } + }; if (isEditing) { - appointmentApi.updateAppointment(appointmentId, dto).enqueue(simpleCallback("Updated")); + appointmentViewModel.updateAppointment(appointmentId, dto).observe(getViewLifecycleOwner(), observer); } else { - appointmentApi.createAppointment(dto).enqueue(simpleCallback("Saved")); + appointmentViewModel.createAppointment(dto).observe(getViewLifecycleOwner(), observer); } } - /** - * callback for appointment save/update operations. - */ - private Callback simpleCallback(String msg) { - return new Callback<>() { - public void onResponse(Call c, Response r) { - Log.d("APPT_SAVE", "Response: " + r.code()); - if (r.isSuccessful()) { - Toast.makeText(getContext(), msg, Toast.LENGTH_SHORT).show(); - navigateBack(); - } else { - try { - String errorBody = r.errorBody().string(); - Log.e("APPT_SAVE", "Error: " + errorBody); - - // Show proper dialog based on error type - if (errorBody.toLowerCase().contains("future")) { - DialogUtils.showInfoDialog(requireContext(), "Invalid Date/Time", - "Booked appointments must be scheduled in the future. " + - "Please select a future date and time."); - } else if (errorBody.toLowerCase().contains("not available") || - errorBody.toLowerCase().contains("time is not available")) { - showNoAvailabilityDialog(); - } else { - ErrorUtils.showErrorMessage(getContext(), r, "Something went wrong. Please try again."); - } - } catch (Exception e) { - Log.e("APPT_SAVE", "Failed to read error body"); - DialogUtils.showInfoDialog(requireContext(), "Error", "Something went wrong. Please try again."); - } - } + private void handleSaveError(String errorMessage) { + if (errorMessage != null) { + Log.e("APPT_SAVE", "Error: " + errorMessage); + if (errorMessage.toLowerCase().contains("future")) { + DialogUtils.showInfoDialog(requireContext(), "Invalid Date/Time", + "Booked appointments must be scheduled in the future."); + } else if (errorMessage.toLowerCase().contains("not available")) { + showNoAvailabilityDialog(); + } else { + Toast.makeText(getContext(), "Operation failed", Toast.LENGTH_SHORT).show(); } - - public void onFailure(Call c, Throwable t) { - Log.e("APPT_SAVE", "Failure: " + t.getMessage()); - Toast.makeText(getContext(), "Network error", Toast.LENGTH_SHORT).show(); - } - }; + } else { + Toast.makeText(getContext(), "Something went wrong", Toast.LENGTH_SHORT).show(); + } } /** @@ -396,7 +347,7 @@ public class AppointmentDetailFragment extends Fragment { private void showNoAvailabilityDialog() { new androidx.appcompat.app.AlertDialog.Builder(requireContext()) .setTitle("No Availability") - .setMessage("This time slot is already booked for the selected service and store. Please choose a different time or date.") + .setMessage("This time slot is already booked. Please choose a different time or date.") .setPositiveButton("Change Time", (d, w) -> d.dismiss()) .setNegativeButton("Cancel Booking", (d, w) -> navigateBack()) .setCancelable(false) @@ -407,14 +358,15 @@ public class AppointmentDetailFragment extends Fragment { * Shows a confirmation dialog and handles the deletion of an appointment. */ private void confirmDelete() { - DialogUtils.showDeleteConfirmDialog(requireContext(), "Appointment", () -> - appointmentApi.deleteAppointment(appointmentId) - .enqueue(new Callback() { - public void onResponse(Call c, Response r) { navigateBack(); } - public void onFailure(Call c, Throwable t) { - Toast.makeText(getContext(), "Delete failed", Toast.LENGTH_SHORT).show(); - } - })); + DialogUtils.showDeleteConfirmDialog(requireContext(), "Appointment", () -> + appointmentViewModel.deleteAppointment(appointmentId).observe(getViewLifecycleOwner(), resource -> { + if (resource.status == Resource.Status.SUCCESS) { + Toast.makeText(getContext(), "Deleted", Toast.LENGTH_SHORT).show(); + navigateBack(); + } else if (resource.status == Resource.Status.ERROR) { + Toast.makeText(getContext(), "Delete failed", Toast.LENGTH_SHORT).show(); + } + })); } /** diff --git a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/InventoryDetailFragment.java b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/InventoryDetailFragment.java index d174f240..e2b0984d 100644 --- a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/InventoryDetailFragment.java +++ b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/InventoryDetailFragment.java @@ -14,30 +14,26 @@ import android.widget.Button; import android.widget.TextView; import android.widget.Toast; +import androidx.annotation.NonNull; import androidx.appcompat.app.AlertDialog; import androidx.fragment.app.Fragment; +import androidx.lifecycle.ViewModelProvider; import androidx.navigation.fragment.NavHostFragment; import com.example.petstoremobile.R; import com.example.petstoremobile.adapters.BlackTextArrayAdapter; -import com.example.petstoremobile.api.InventoryApi; -import com.example.petstoremobile.api.ProductApi; import com.example.petstoremobile.dtos.InventoryDTO; import com.example.petstoremobile.dtos.InventoryRequest; -import com.example.petstoremobile.dtos.PageResponse; import com.example.petstoremobile.dtos.ProductDTO; -import com.example.petstoremobile.utils.ErrorUtils; import com.example.petstoremobile.utils.InputValidator; +import com.example.petstoremobile.utils.Resource; +import com.example.petstoremobile.viewmodels.InventoryViewModel; +import com.example.petstoremobile.viewmodels.ProductViewModel; import java.util.ArrayList; import java.util.List; -import javax.inject.Inject; - import dagger.hilt.android.AndroidEntryPoint; -import retrofit2.Call; -import retrofit2.Callback; -import retrofit2.Response; /** * Fragment for displaying and editing inventory item details. @@ -50,8 +46,8 @@ public class InventoryDetailFragment extends Fragment { private android.widget.EditText etQuantity; private Button btnSave, btnDelete, btnBack; - @Inject InventoryApi inventoryApi; - @Inject ProductApi productApi; + private InventoryViewModel inventoryViewModel; + private ProductViewModel productViewModel; private boolean isEditing = false; private long inventoryId = -1; @@ -68,7 +64,14 @@ public class InventoryDetailFragment extends Fragment { private ArrayAdapter dropdownAdapter; @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + inventoryViewModel = new ViewModelProvider(this).get(InventoryViewModel.class); + productViewModel = new ViewModelProvider(this).get(ProductViewModel.class); + } + + @Override + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_inventory_detail, container, false); @@ -150,30 +153,21 @@ public class InventoryDetailFragment extends Fragment { * Searches for products matching the query from the backend. */ private void searchProducts(String query) { - productApi.getAllProducts(query, 0, 20).enqueue(new Callback>() { - @Override - public void onResponse(Call> call, - Response> response) { - if (response.isSuccessful() && response.body() != null) { - productSuggestions.clear(); - productSuggestions.addAll(response.body().getContent()); + productViewModel.getAllProducts(query, 0, 20).observe(getViewLifecycleOwner(), resource -> { + if (resource.status == Resource.Status.SUCCESS && resource.data != null) { + productSuggestions.clear(); + productSuggestions.addAll(resource.data.getContent()); - // Build display strings: "Product Name (ID: X)" - List names = new ArrayList<>(); - for (ProductDTO p : productSuggestions) { - names.add(p.getProdName() + " (ID: " + p.getProdId() + ")"); - } - - dropdownAdapter.clear(); - dropdownAdapter.addAll(names); - dropdownAdapter.notifyDataSetChanged(); - etProductSearch.showDropDown(); + // Build display strings: "Product Name (ID: X)" + List names = new ArrayList<>(); + for (ProductDTO p : productSuggestions) { + names.add(p.getProdName() + " (ID: " + p.getProdId() + ")"); } - } - @Override - public void onFailure(Call> call, Throwable t) { - Toast.makeText(getContext(), "Failed to load products", Toast.LENGTH_SHORT).show(); + dropdownAdapter.clear(); + dropdownAdapter.addAll(names); + dropdownAdapter.notifyDataSetChanged(); + etProductSearch.showDropDown(); } }); } @@ -242,41 +236,23 @@ public class InventoryDetailFragment extends Fragment { setButtonsEnabled(false); if (isEditing) { - inventoryApi.updateInventory(inventoryId, request).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - setButtonsEnabled(true); - if (response.isSuccessful()) { - Toast.makeText(getContext(), "Inventory updated", Toast.LENGTH_SHORT).show(); - navigateBack(); - } else { - ErrorUtils.showErrorMessage(getContext(), response, "Update failed"); - } - } - - @Override - public void onFailure(Call call, Throwable t) { - setButtonsEnabled(true); - Toast.makeText(getContext(), "Network error", Toast.LENGTH_SHORT).show(); + inventoryViewModel.updateInventory(inventoryId, request).observe(getViewLifecycleOwner(), resource -> { + setButtonsEnabled(true); + if (resource.status == Resource.Status.SUCCESS) { + Toast.makeText(getContext(), "Inventory updated", Toast.LENGTH_SHORT).show(); + navigateBack(); + } else if (resource.status == Resource.Status.ERROR) { + Toast.makeText(getContext(), "Error: " + resource.message, Toast.LENGTH_SHORT).show(); } }); } else { - inventoryApi.createInventory(request).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - setButtonsEnabled(true); - if (response.isSuccessful()) { - Toast.makeText(getContext(), "Inventory created", Toast.LENGTH_SHORT).show(); - navigateBack(); - } else { - ErrorUtils.showErrorMessage(getContext(), response, "Create failed"); - } - } - - @Override - public void onFailure(Call call, Throwable t) { - setButtonsEnabled(true); - Toast.makeText(getContext(), "Network error", Toast.LENGTH_SHORT).show(); + inventoryViewModel.createInventory(request).observe(getViewLifecycleOwner(), resource -> { + setButtonsEnabled(true); + if (resource.status == Resource.Status.SUCCESS) { + Toast.makeText(getContext(), "Inventory created", Toast.LENGTH_SHORT).show(); + navigateBack(); + } else if (resource.status == Resource.Status.ERROR) { + Toast.makeText(getContext(), "Error: " + resource.message, Toast.LENGTH_SHORT).show(); } }); } @@ -299,22 +275,13 @@ public class InventoryDetailFragment extends Fragment { */ private void deleteInventory() { setButtonsEnabled(false); - inventoryApi.deleteInventory(inventoryId).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - setButtonsEnabled(true); - if (response.isSuccessful()) { - Toast.makeText(getContext(), "Inventory deleted", Toast.LENGTH_SHORT).show(); - navigateBack(); - } else { - ErrorUtils.showErrorMessage(getContext(), response, "Delete failed"); - } - } - - @Override - public void onFailure(Call call, Throwable t) { - setButtonsEnabled(true); - Toast.makeText(getContext(), "Network error", Toast.LENGTH_SHORT).show(); + inventoryViewModel.deleteInventory(inventoryId).observe(getViewLifecycleOwner(), resource -> { + setButtonsEnabled(true); + if (resource.status == Resource.Status.SUCCESS) { + Toast.makeText(getContext(), "Inventory deleted", Toast.LENGTH_SHORT).show(); + navigateBack(); + } else if (resource.status == Resource.Status.ERROR) { + Toast.makeText(getContext(), "Delete failed: " + resource.message, Toast.LENGTH_SHORT).show(); } }); } diff --git a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/PetDetailFragment.java b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/PetDetailFragment.java index 78d5efb7..afff4dd1 100644 --- a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/PetDetailFragment.java +++ b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/PetDetailFragment.java @@ -4,9 +4,9 @@ import android.os.Bundle; import androidx.annotation.NonNull; import androidx.fragment.app.Fragment; +import androidx.lifecycle.ViewModelProvider; import androidx.navigation.fragment.NavHostFragment; -import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -17,20 +17,15 @@ import android.widget.TextView; import android.widget.Toast; import com.example.petstoremobile.R; -import com.example.petstoremobile.api.PetApi; import com.example.petstoremobile.dtos.PetDTO; import com.example.petstoremobile.utils.ActivityLogger; import com.example.petstoremobile.utils.DialogUtils; -import com.example.petstoremobile.utils.ErrorUtils; import com.example.petstoremobile.utils.InputValidator; +import com.example.petstoremobile.utils.Resource; import com.example.petstoremobile.utils.SpinnerUtils; - -import javax.inject.Inject; +import com.example.petstoremobile.viewmodels.PetViewModel; import dagger.hilt.android.AndroidEntryPoint; -import retrofit2.Call; -import retrofit2.Callback; -import retrofit2.Response; /** * Fragment for displaying and editing pet details. @@ -45,7 +40,13 @@ public class PetDetailFragment extends Fragment { private int petId; private boolean isEditing = false; - @Inject PetApi petApi; + private PetViewModel viewModel; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + viewModel = new ViewModelProvider(this).get(PetViewModel.class); + } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, @@ -97,44 +98,24 @@ public class PetDetailFragment extends Fragment { if (isEditing) { // Update existing pet petDTO.setPetId((long) petId); - petApi.updatePet((long) petId, petDTO).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful()) { - ActivityLogger.logChange(requireContext(), "Pet", "UPDATED", petId); - Toast.makeText(getContext(), "Pet updated successfully!", Toast.LENGTH_SHORT).show(); - navigateBack(); - } else { - ErrorUtils.showErrorMessage(getContext(), response, "Failed to update pet"); - } - } - - @Override - public void onFailure(Call call, Throwable t) { - ActivityLogger.logException(requireContext(), "PetDetailFragment.updatePet", new Exception(t)); - Log.e("PetDetailFragment", "Error updating pet", t); - Toast.makeText(getContext(), "Network error: " + t.getMessage(), Toast.LENGTH_SHORT).show(); + viewModel.updatePet((long) petId, petDTO).observe(getViewLifecycleOwner(), resource -> { + if (resource.status == Resource.Status.SUCCESS) { + ActivityLogger.logChange(requireContext(), "Pet", "UPDATED", petId); + Toast.makeText(getContext(), "Pet updated successfully!", Toast.LENGTH_SHORT).show(); + navigateBack(); + } else if (resource.status == Resource.Status.ERROR) { + Toast.makeText(getContext(), "Error: " + resource.message, Toast.LENGTH_SHORT).show(); } }); } else { // Add new pet - petApi.createPet(petDTO).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful()) { - ActivityLogger.log(requireContext(), "Added new Pet: " + name); - Toast.makeText(getContext(), "Pet added successfully!", Toast.LENGTH_SHORT).show(); - navigateBack(); - } else { - ErrorUtils.showErrorMessage(getContext(), response, "Failed to add pet"); - } - } - - @Override - public void onFailure(Call call, Throwable t) { - ActivityLogger.logException(requireContext(), "PetDetailFragment.createPet", new Exception(t)); - Log.e("PetDetailFragment", "Error adding pet", t); - Toast.makeText(getContext(), "Network error: " + t.getMessage(), Toast.LENGTH_SHORT).show(); + viewModel.createPet(petDTO).observe(getViewLifecycleOwner(), resource -> { + if (resource.status == Resource.Status.SUCCESS) { + ActivityLogger.log(requireContext(), "Added new Pet: " + name); + Toast.makeText(getContext(), "Pet added successfully!", Toast.LENGTH_SHORT).show(); + navigateBack(); + } else if (resource.status == Resource.Status.ERROR) { + Toast.makeText(getContext(), "Error: " + resource.message, Toast.LENGTH_SHORT).show(); } }); } @@ -145,23 +126,13 @@ public class PetDetailFragment extends Fragment { */ private void deletePet() { DialogUtils.showDeleteConfirmDialog(requireContext(), "Pet", () -> - petApi.deletePet((long) petId).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful()) { - ActivityLogger.logChange(requireContext(), "Pet", "DELETED", petId); - Toast.makeText(getContext(), "Pet deleted successfully!", Toast.LENGTH_SHORT).show(); - navigateBack(); - } else { - ErrorUtils.showErrorMessage(getContext(), response, "Failed to delete pet"); - } - } - - @Override - public void onFailure(Call call, Throwable t) { - ActivityLogger.logException(requireContext(), "PetDetailFragment.deletePet", new Exception(t)); - Log.e("PetDetailFragment", "Error deleting pet", t); - Toast.makeText(getContext(), "Network error: " + t.getMessage(), Toast.LENGTH_SHORT).show(); + viewModel.deletePet((long) petId).observe(getViewLifecycleOwner(), resource -> { + if (resource.status == Resource.Status.SUCCESS) { + ActivityLogger.logChange(requireContext(), "Pet", "DELETED", petId); + Toast.makeText(getContext(), "Pet deleted successfully!", Toast.LENGTH_SHORT).show(); + navigateBack(); + } else if (resource.status == Resource.Status.ERROR) { + Toast.makeText(getContext(), "Delete failed: " + resource.message, Toast.LENGTH_SHORT).show(); } })); } @@ -189,9 +160,7 @@ public class PetDetailFragment extends Fragment { etPetBreed.setText(getArguments().getString("petBreed")); etPetAge.setText(String.valueOf(getArguments().getInt("petAge"))); etPetPrice.setText(String.valueOf(getArguments().getDouble("petPrice"))); - SpinnerUtils.setSelectionByValue(spinnerPetStatus, getArguments().getString("petStatus")); - btnDeletePet.setVisibility(View.VISIBLE); } else { // Pet is being added @@ -228,5 +197,4 @@ public class PetDetailFragment extends Fragment { SpinnerUtils.setupStringSpinner(requireContext(), spinnerPetStatus, new String[]{"Available", "Adopted"}); } - } diff --git a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/ProductSupplierDetailFragment.java b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/ProductSupplierDetailFragment.java index 3db78dd0..bee0873d 100644 --- a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/ProductSupplierDetailFragment.java +++ b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/ProductSupplierDetailFragment.java @@ -1,31 +1,30 @@ package com.example.petstoremobile.fragments.listfragments.detailfragments; import android.os.Bundle; -import android.util.Log; import android.view.*; import android.widget.*; import androidx.annotation.NonNull; import androidx.fragment.app.Fragment; +import androidx.lifecycle.ViewModelProvider; import androidx.navigation.fragment.NavHostFragment; import com.example.petstoremobile.R; -import com.example.petstoremobile.api.*; import com.example.petstoremobile.dtos.*; import com.example.petstoremobile.utils.DialogUtils; -import com.example.petstoremobile.utils.ErrorUtils; import com.example.petstoremobile.utils.InputValidator; +import com.example.petstoremobile.utils.Resource; import com.example.petstoremobile.utils.SpinnerUtils; +import com.example.petstoremobile.viewmodels.ProductSupplierViewModel; +import com.example.petstoremobile.viewmodels.ProductViewModel; +import com.example.petstoremobile.viewmodels.SupplierViewModel; import java.math.BigDecimal; import java.util.*; -import javax.inject.Inject; - import dagger.hilt.android.AndroidEntryPoint; -import retrofit2.*; /** - * Fragment for displaying and editing the relationship between products and suppliers, + * Fragment for displaying and editing the relationship between products and suppliers. */ @AndroidEntryPoint public class ProductSupplierDetailFragment extends Fragment { @@ -44,9 +43,17 @@ public class ProductSupplierDetailFragment extends Fragment { private List productList = new ArrayList<>(); private List supplierList = new ArrayList<>(); - @Inject ProductSupplierApi productSupplierApi; - @Inject ProductApi productApi; - @Inject SupplierApi supplierApi; + private ProductSupplierViewModel psViewModel; + private ProductViewModel productViewModel; + private SupplierViewModel supplierViewModel; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + psViewModel = new ViewModelProvider(this).get(ProductSupplierViewModel.class); + productViewModel = new ViewModelProvider(this).get(ProductViewModel.class); + supplierViewModel = new ViewModelProvider(this).get(SupplierViewModel.class); + } @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, @@ -87,42 +94,28 @@ public class ProductSupplierDetailFragment extends Fragment { * Loads the list of products from the API. */ private void loadProducts() { - productApi.getAllProducts(null, 0, 200) - .enqueue(new Callback>() { - public void onResponse(Call> c, - Response> r) { - if (r.isSuccessful() && r.body() != null) { - productList = r.body().getContent(); - SpinnerUtils.populateSpinner(requireContext(), spinnerProduct, productList, - ProductDTO::getProdName, "-- Select Product --", - preselectedProductId, ProductDTO::getProdId); - } - } - public void onFailure(Call> c, Throwable t) { - Log.e("PSDetail", "Product load failed: " + t.getMessage()); - } - }); + productViewModel.getAllProducts(null, 0, 200).observe(getViewLifecycleOwner(), resource -> { + if (resource.status == Resource.Status.SUCCESS && resource.data != null) { + productList = resource.data.getContent(); + SpinnerUtils.populateSpinner(requireContext(), spinnerProduct, productList, + ProductDTO::getProdName, "-- Select Product --", + preselectedProductId, ProductDTO::getProdId); + } + }); } /** * Loads the list of suppliers from the API. */ private void loadSuppliers() { - supplierApi.getAllSuppliers(0, 200) - .enqueue(new Callback>() { - public void onResponse(Call> c, - Response> r) { - if (r.isSuccessful() && r.body() != null) { - supplierList = r.body().getContent(); - SpinnerUtils.populateSpinner(requireContext(), spinnerSupplier, supplierList, - SupplierDTO::getSupCompany, "-- Select Supplier --", - preselectedSupplierId, SupplierDTO::getSupId); - } - } - public void onFailure(Call> c, Throwable t) { - Log.e("PSDetail", "Supplier load failed: " + t.getMessage()); - } - }); + supplierViewModel.getAllSuppliers(0, 200).observe(getViewLifecycleOwner(), resource -> { + if (resource.status == Resource.Status.SUCCESS && resource.data != null) { + supplierList = resource.data.getContent(); + SpinnerUtils.populateSpinner(requireContext(), spinnerSupplier, supplierList, + SupplierDTO::getSupCompany, "-- Select Supplier --", + preselectedSupplierId, SupplierDTO::getSupId); + } + }); } /** @@ -169,48 +162,39 @@ public class ProductSupplierDetailFragment extends Fragment { product.getProdId(), supplier.getSupId(), cost); if (isEditing) { - productSupplierApi.updateProductSupplier(editProductId, editSupplierId, dto) - .enqueue(simpleCallback("Updated")); - } else { - productSupplierApi.createProductSupplier(dto).enqueue(simpleCallback("Saved")); - } - } - - /** - * callback for product-supplier save/update operations. - */ - 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(); + psViewModel.updateProductSupplier(editProductId, editSupplierId, dto).observe(getViewLifecycleOwner(), resource -> { + if (resource.status == Resource.Status.SUCCESS) { + Toast.makeText(getContext(), "Updated", Toast.LENGTH_SHORT).show(); navigateBack(); - } else { - ErrorUtils.showErrorMessage(getContext(), r, "Error " + r.code()); + } else if (resource.status == Resource.Status.ERROR) { + Toast.makeText(getContext(), "Error: " + resource.message, Toast.LENGTH_SHORT).show(); } - } - public void onFailure(Call c, Throwable t) { - Log.e("PS_SAVE", "Failure: " + t.getMessage()); - Toast.makeText(getContext(), "Network error", Toast.LENGTH_SHORT).show(); - } - }; + }); + } else { + psViewModel.createProductSupplier(dto).observe(getViewLifecycleOwner(), resource -> { + if (resource.status == Resource.Status.SUCCESS) { + Toast.makeText(getContext(), "Saved", Toast.LENGTH_SHORT).show(); + navigateBack(); + } else if (resource.status == Resource.Status.ERROR) { + Toast.makeText(getContext(), "Error: " + resource.message, Toast.LENGTH_SHORT).show(); + } + }); + } } /** * Shows a confirmation dialog before deleting a product-supplier relationship. */ private void confirmDelete() { - DialogUtils.showDeleteConfirmDialog(requireContext(), "Product Supplier", () -> - productSupplierApi.deleteProductSupplier(editProductId, editSupplierId) - .enqueue(new Callback() { - public void onResponse(Call c, Response r) { - navigateBack(); - } - public void onFailure(Call c, Throwable t) { - Toast.makeText(getContext(), "Delete failed", - Toast.LENGTH_SHORT).show(); - } - })); + DialogUtils.showDeleteConfirmDialog(requireContext(), "Product Supplier", () -> + psViewModel.deleteProductSupplier(editProductId, editSupplierId).observe(getViewLifecycleOwner(), resource -> { + if (resource.status == Resource.Status.SUCCESS) { + Toast.makeText(getContext(), "Deleted", Toast.LENGTH_SHORT).show(); + navigateBack(); + } else if (resource.status == Resource.Status.ERROR) { + Toast.makeText(getContext(), "Delete failed: " + resource.message, Toast.LENGTH_SHORT).show(); + } + })); } /** diff --git a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/ServiceDetailFragment.java b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/ServiceDetailFragment.java index a70cb266..5cb9a7c2 100644 --- a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/ServiceDetailFragment.java +++ b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/ServiceDetailFragment.java @@ -2,10 +2,11 @@ package com.example.petstoremobile.fragments.listfragments.detailfragments; import android.os.Bundle; +import androidx.annotation.NonNull; import androidx.fragment.app.Fragment; +import androidx.lifecycle.ViewModelProvider; import androidx.navigation.fragment.NavHostFragment; -import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -15,19 +16,14 @@ import android.widget.TextView; import android.widget.Toast; import com.example.petstoremobile.R; -import com.example.petstoremobile.api.ServiceApi; import com.example.petstoremobile.dtos.ServiceDTO; import com.example.petstoremobile.utils.ActivityLogger; import com.example.petstoremobile.utils.DialogUtils; -import com.example.petstoremobile.utils.ErrorUtils; import com.example.petstoremobile.utils.InputValidator; - -import javax.inject.Inject; +import com.example.petstoremobile.utils.Resource; +import com.example.petstoremobile.viewmodels.ServiceViewModel; import dagger.hilt.android.AndroidEntryPoint; -import retrofit2.Call; -import retrofit2.Callback; -import retrofit2.Response; /** * Fragment for displaying and editing service details. @@ -41,10 +37,16 @@ public class ServiceDetailFragment extends Fragment { private int serviceId; private boolean isEditing = false; - @Inject ServiceApi serviceApi; + private ServiceViewModel viewModel; @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + viewModel = new ViewModelProvider(this).get(ServiceViewModel.class); + } + + @Override + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_service_detail, container, false); @@ -87,44 +89,23 @@ public class ServiceDetailFragment extends Fragment { if (isEditing) { // Update existing service serviceDTO.setServiceId((long) serviceId); - serviceApi.updateService((long) serviceId, serviceDTO).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful()) { - ActivityLogger.logChange(requireContext(), "Service", "UPDATED", serviceId); - Toast.makeText(getContext(), "Service updated successfully!", Toast.LENGTH_SHORT).show(); - navigateBack(); - } else { - ErrorUtils.showErrorMessage(getContext(), response, "Failed to update service"); - } - } - - @Override - public void onFailure(Call call, Throwable t) { - ActivityLogger.logException(requireContext(), "ServiceDetailFragment.updateService", new Exception(t)); - Log.e("ServiceDetailFragment", "Error updating service", t); - Toast.makeText(getContext(), "Network error: " + t.getMessage(), Toast.LENGTH_SHORT).show(); + viewModel.updateService((long) serviceId, serviceDTO).observe(getViewLifecycleOwner(), resource -> { + if (resource.status == Resource.Status.SUCCESS) { + ActivityLogger.logChange(requireContext(), "Service", "UPDATED", serviceId); + Toast.makeText(getContext(), "Service updated successfully!", Toast.LENGTH_SHORT).show(); + navigateBack(); + } else if (resource.status == Resource.Status.ERROR) { + Toast.makeText(getContext(), "Error: " + resource.message, Toast.LENGTH_SHORT).show(); } }); } else { - // Add new service - serviceApi.createService(serviceDTO).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful()) { - ActivityLogger.log(requireContext(), "Added new Service: " + name); - Toast.makeText(getContext(), "Service added successfully!", Toast.LENGTH_SHORT).show(); - navigateBack(); - } else { - ErrorUtils.showErrorMessage(getContext(), response, "Failed to add service"); - } - } - - @Override - public void onFailure(Call call, Throwable t) { - ActivityLogger.logException(requireContext(), "ServiceDetailFragment.createService", new Exception(t)); - Log.e("ServiceDetailFragment", "Error adding service", t); - Toast.makeText(getContext(), "Network error: " + t.getMessage(), Toast.LENGTH_SHORT).show(); + viewModel.createService(serviceDTO).observe(getViewLifecycleOwner(), resource -> { + if (resource.status == Resource.Status.SUCCESS) { + ActivityLogger.log(requireContext(), "Added new Service: " + name); + Toast.makeText(getContext(), "Service added successfully!", Toast.LENGTH_SHORT).show(); + navigateBack(); + } else if (resource.status == Resource.Status.ERROR) { + Toast.makeText(getContext(), "Error: " + resource.message, Toast.LENGTH_SHORT).show(); } }); } @@ -135,23 +116,13 @@ public class ServiceDetailFragment extends Fragment { */ private void deleteService() { DialogUtils.showDeleteConfirmDialog(requireContext(), "Service", () -> - serviceApi.deleteService((long) serviceId).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful()) { - ActivityLogger.logChange(requireContext(), "Service", "DELETED", serviceId); - Toast.makeText(getContext(), "Service deleted successfully!", Toast.LENGTH_SHORT).show(); - navigateBack(); - } else { - ErrorUtils.showErrorMessage(getContext(), response, "Failed to delete service"); - } - } - - @Override - public void onFailure(Call call, Throwable t) { - ActivityLogger.logException(requireContext(), "ServiceDetailFragment.deleteService", new Exception(t)); - Log.e("ServiceDetailFragment", "Error deleting service", t); - Toast.makeText(getContext(), "Network error: " + t.getMessage(), Toast.LENGTH_SHORT).show(); + viewModel.deleteService((long) serviceId).observe(getViewLifecycleOwner(), resource -> { + if (resource.status == Resource.Status.SUCCESS) { + ActivityLogger.logChange(requireContext(), "Service", "DELETED", serviceId); + Toast.makeText(getContext(), "Service deleted successfully!", Toast.LENGTH_SHORT).show(); + navigateBack(); + } else if (resource.status == Resource.Status.ERROR) { + Toast.makeText(getContext(), "Delete failed: " + resource.message, Toast.LENGTH_SHORT).show(); } })); } diff --git a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/SupplierDetailFragment.java b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/SupplierDetailFragment.java index 3001faad..4477712f 100644 --- a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/SupplierDetailFragment.java +++ b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/SupplierDetailFragment.java @@ -2,10 +2,11 @@ package com.example.petstoremobile.fragments.listfragments.detailfragments; import android.os.Bundle; +import androidx.annotation.NonNull; import androidx.fragment.app.Fragment; +import androidx.lifecycle.ViewModelProvider; import androidx.navigation.fragment.NavHostFragment; -import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -15,20 +16,15 @@ import android.widget.TextView; import android.widget.Toast; import com.example.petstoremobile.R; -import com.example.petstoremobile.api.SupplierApi; import com.example.petstoremobile.dtos.SupplierDTO; import com.example.petstoremobile.utils.ActivityLogger; import com.example.petstoremobile.utils.DialogUtils; -import com.example.petstoremobile.utils.ErrorUtils; import com.example.petstoremobile.utils.InputValidator; +import com.example.petstoremobile.utils.Resource; import com.example.petstoremobile.utils.UIUtils; - -import javax.inject.Inject; +import com.example.petstoremobile.viewmodels.SupplierViewModel; import dagger.hilt.android.AndroidEntryPoint; -import retrofit2.Call; -import retrofit2.Callback; -import retrofit2.Response; /** * Fragment for displaying and editing supplier details. @@ -42,10 +38,16 @@ public class SupplierDetailFragment extends Fragment { private int supId; private boolean isEditing = false; - @Inject SupplierApi supplierApi; + private SupplierViewModel viewModel; @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + viewModel = new ViewModelProvider(this).get(SupplierViewModel.class); + } + + @Override + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_supplier_detail, container, false); @@ -91,44 +93,24 @@ public class SupplierDetailFragment extends Fragment { if (isEditing) { // Update existing supplier supplierDTO.setSupId((long) supId); - supplierApi.updateSupplier((long) supId, supplierDTO).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful()) { - ActivityLogger.logChange(requireContext(), "Supplier", "UPDATED", supId); - Toast.makeText(getContext(), "Supplier updated successfully!", Toast.LENGTH_SHORT).show(); - navigateBack(); - } else { - ErrorUtils.showErrorMessage(getContext(), response, "Failed to update supplier"); - } - } - - @Override - public void onFailure(Call call, Throwable t) { - ActivityLogger.logException(requireContext(), "SupplierDetailFragment.updateSupplier", new Exception(t)); - Log.e("SupplierDetailFragment", "Error updating supplier", t); - Toast.makeText(getContext(), "Network error: " + t.getMessage(), Toast.LENGTH_SHORT).show(); + viewModel.updateSupplier((long) supId, supplierDTO).observe(getViewLifecycleOwner(), resource -> { + if (resource.status == Resource.Status.SUCCESS) { + ActivityLogger.logChange(requireContext(), "Supplier", "UPDATED", supId); + Toast.makeText(getContext(), "Supplier updated successfully!", Toast.LENGTH_SHORT).show(); + navigateBack(); + } else if (resource.status == Resource.Status.ERROR) { + Toast.makeText(getContext(), "Error: " + resource.message, Toast.LENGTH_SHORT).show(); } }); } else { // Add new supplier - supplierApi.createSupplier(supplierDTO).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful()) { - ActivityLogger.log(requireContext(), "Added new Supplier: " + company); - Toast.makeText(getContext(), "Supplier added successfully!", Toast.LENGTH_SHORT).show(); - navigateBack(); - } else { - ErrorUtils.showErrorMessage(getContext(), response, "Failed to add supplier"); - } - } - - @Override - public void onFailure(Call call, Throwable t) { - ActivityLogger.logException(requireContext(), "SupplierDetailFragment.createSupplier", new Exception(t)); - Log.e("SupplierDetailFragment", "Error adding supplier", t); - Toast.makeText(getContext(), "Network error: " + t.getMessage(), Toast.LENGTH_SHORT).show(); + viewModel.createSupplier(supplierDTO).observe(getViewLifecycleOwner(), resource -> { + if (resource.status == Resource.Status.SUCCESS) { + ActivityLogger.log(requireContext(), "Added new Supplier: " + company); + Toast.makeText(getContext(), "Supplier added successfully!", Toast.LENGTH_SHORT).show(); + navigateBack(); + } else if (resource.status == Resource.Status.ERROR) { + Toast.makeText(getContext(), "Error: " + resource.message, Toast.LENGTH_SHORT).show(); } }); } @@ -138,24 +120,14 @@ public class SupplierDetailFragment extends Fragment { * Displays a confirmation dialog and handles the deletion of a supplier. */ private void deleteSupplier() { - DialogUtils.showDeleteConfirmDialog(requireContext(), "Supplier", () -> - supplierApi.deleteSupplier((long) supId).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful()) { - ActivityLogger.logChange(requireContext(), "Supplier", "DELETED", supId); - Toast.makeText(getContext(), "Supplier deleted successfully!", Toast.LENGTH_SHORT).show(); - navigateBack(); - } else { - ErrorUtils.showErrorMessage(getContext(), response, "Failed to delete supplier"); - } - } - - @Override - public void onFailure(Call call, Throwable t) { - ActivityLogger.logException(requireContext(), "SupplierDetailFragment.deleteSupplier", new Exception(t)); - Log.e("SupplierDetailFragment", "Error deleting supplier", t); - Toast.makeText(getContext(), "Network error: " + t.getMessage(), Toast.LENGTH_SHORT).show(); + DialogUtils.showDeleteConfirmDialog(requireContext(), "Supplier", () -> + viewModel.deleteSupplier((long) supId).observe(getViewLifecycleOwner(), resource -> { + if (resource.status == Resource.Status.SUCCESS) { + ActivityLogger.logChange(requireContext(), "Supplier", "DELETED", supId); + Toast.makeText(getContext(), "Supplier deleted successfully!", Toast.LENGTH_SHORT).show(); + navigateBack(); + } else if (resource.status == Resource.Status.ERROR) { + Toast.makeText(getContext(), "Delete failed: " + resource.message, Toast.LENGTH_SHORT).show(); } })); } 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 57915e29..0ddc0511 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 @@ -13,7 +13,6 @@ import android.view.ViewGroup; import android.widget.Button; import android.widget.ImageView; import android.widget.TextView; -import android.widget.Toast; import com.example.petstoremobile.R; import com.example.petstoremobile.api.PetApi; @@ -21,6 +20,7 @@ import com.example.petstoremobile.api.auth.TokenManager; import com.example.petstoremobile.utils.FileUtils; import com.example.petstoremobile.utils.GlideUtils; import com.example.petstoremobile.utils.ImagePickerHelper; +import com.example.petstoremobile.utils.RetrofitUtils; import java.io.File; import java.util.Locale; @@ -32,9 +32,6 @@ import dagger.hilt.android.AndroidEntryPoint; import okhttp3.MediaType; import okhttp3.MultipartBody; import okhttp3.RequestBody; -import retrofit2.Call; -import retrofit2.Callback; -import retrofit2.Response; @AndroidEntryPoint public class PetProfileFragment extends Fragment { @@ -157,24 +154,12 @@ public class PetProfileFragment extends Fragment { MultipartBody.Part body = MultipartBody.Part.createFormData("image", file.getName(), requestFile); // Call the backend to upload the image - petApi.uploadPetImage((long) petId, body).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful()) { - Toast.makeText(requireContext(), "Pet photo updated successfully", Toast.LENGTH_SHORT).show(); - // Reload image after successful upload - loadPetImage(petId); - } else { - Toast.makeText(requireContext(), "Failed to upload pet photo", Toast.LENGTH_SHORT).show(); - } - } - - @Override - public void onFailure(Call call, Throwable t) { - Log.e("UPLOAD_PET_IMAGE", "Failure: " + t.getMessage()); - Toast.makeText(requireContext(), "Network error", Toast.LENGTH_SHORT).show(); - } - }); + petApi.uploadPetImage((long) petId, body).enqueue(RetrofitUtils.createCallback( + requireContext(), + "UPLOAD_PET_IMAGE", + "Pet photo updated successfully", + result -> loadPetImage(petId) + )); } catch (Exception e) { Log.e("UPLOAD_PET_IMAGE", "Error: " + e.getMessage()); } @@ -184,23 +169,14 @@ public class PetProfileFragment extends Fragment { * Sends a request to the API to remove the current pet photo. */ private void deletePetImage() { - petApi.deletePetImage((long) petId).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful()) { - Toast.makeText(requireContext(), "Pet photo removed", Toast.LENGTH_SHORT).show(); + petApi.deletePetImage((long) petId).enqueue(RetrofitUtils.createCallback( + requireContext(), + "DELETE_PET_IMAGE", + "Pet photo removed", + result -> { hasImage = false; imgPet.setImageResource(R.drawable.placeholder); - } else { - Toast.makeText(requireContext(), "Failed to remove pet photo", Toast.LENGTH_SHORT).show(); } - } - - @Override - public void onFailure(Call call, Throwable t) { - Log.e("DELETE_PET_IMAGE", "Failure: " + t.getMessage()); - Toast.makeText(requireContext(), "Network error", Toast.LENGTH_SHORT).show(); - } - }); + )); } } diff --git a/android/app/src/main/java/com/example/petstoremobile/repositories/AdoptionRepository.java b/android/app/src/main/java/com/example/petstoremobile/repositories/AdoptionRepository.java index 8164d34b..8e47788e 100644 --- a/android/app/src/main/java/com/example/petstoremobile/repositories/AdoptionRepository.java +++ b/android/app/src/main/java/com/example/petstoremobile/repositories/AdoptionRepository.java @@ -7,16 +7,14 @@ import com.example.petstoremobile.api.AdoptionApi; import com.example.petstoremobile.dtos.AdoptionDTO; import com.example.petstoremobile.dtos.PageResponse; import com.example.petstoremobile.utils.Resource; +import com.example.petstoremobile.utils.RetrofitUtils; import javax.inject.Inject; import javax.inject.Singleton; -import retrofit2.Call; -import retrofit2.Callback; -import retrofit2.Response; - @Singleton public class AdoptionRepository { + private static final String TAG = "AdoptionRepository"; private final AdoptionApi adoptionApi; @Inject @@ -31,21 +29,8 @@ public class AdoptionRepository { MutableLiveData>> data = new MutableLiveData<>(); data.setValue(Resource.loading(null)); - adoptionApi.getAllAdoptions(page, size).enqueue(new Callback>() { - @Override - public void onResponse(Call> call, Response> response) { - if (response.isSuccessful() && response.body() != null) { - data.setValue(Resource.success(response.body())); - } else { - data.setValue(Resource.error("Error: " + response.message(), null)); - } - } - - @Override - public void onFailure(Call> call, Throwable t) { - data.setValue(Resource.error(t.getMessage(), null)); - } - }); + adoptionApi.getAllAdoptions(page, size).enqueue(RetrofitUtils.createSilentCallback(TAG, + result -> data.setValue(Resource.success(result)))); return data; } @@ -57,21 +42,8 @@ public class AdoptionRepository { MutableLiveData> data = new MutableLiveData<>(); data.setValue(Resource.loading(null)); - adoptionApi.getAdoptionById(id).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful() && response.body() != null) { - data.setValue(Resource.success(response.body())); - } else { - data.setValue(Resource.error("Error: " + response.message(), null)); - } - } - - @Override - public void onFailure(Call call, Throwable t) { - data.setValue(Resource.error(t.getMessage(), null)); - } - }); + adoptionApi.getAdoptionById(id).enqueue(RetrofitUtils.createSilentCallback(TAG, + result -> data.setValue(Resource.success(result)))); return data; } @@ -83,21 +55,8 @@ public class AdoptionRepository { MutableLiveData> data = new MutableLiveData<>(); data.setValue(Resource.loading(null)); - adoptionApi.createAdoption(adoption).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful() && response.body() != null) { - data.setValue(Resource.success(response.body())); - } else { - data.setValue(Resource.error("Error: " + response.message(), null)); - } - } - - @Override - public void onFailure(Call call, Throwable t) { - data.setValue(Resource.error(t.getMessage(), null)); - } - }); + adoptionApi.createAdoption(adoption).enqueue(RetrofitUtils.createSilentCallback(TAG, + result -> data.setValue(Resource.success(result)))); return data; } @@ -109,21 +68,8 @@ public class AdoptionRepository { MutableLiveData> data = new MutableLiveData<>(); data.setValue(Resource.loading(null)); - adoptionApi.updateAdoption(id, adoption).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful() && response.body() != null) { - data.setValue(Resource.success(response.body())); - } else { - data.setValue(Resource.error("Error: " + response.message(), null)); - } - } - - @Override - public void onFailure(Call call, Throwable t) { - data.setValue(Resource.error(t.getMessage(), null)); - } - }); + adoptionApi.updateAdoption(id, adoption).enqueue(RetrofitUtils.createSilentCallback(TAG, + result -> data.setValue(Resource.success(result)))); return data; } @@ -135,21 +81,8 @@ public class AdoptionRepository { MutableLiveData> data = new MutableLiveData<>(); data.setValue(Resource.loading(null)); - adoptionApi.deleteAdoption(id).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful()) { - data.setValue(Resource.success(null)); - } else { - data.setValue(Resource.error("Error: " + response.message(), null)); - } - } - - @Override - public void onFailure(Call call, Throwable t) { - data.setValue(Resource.error(t.getMessage(), null)); - } - }); + adoptionApi.deleteAdoption(id).enqueue(RetrofitUtils.createSilentCallback(TAG, + result -> data.setValue(Resource.success(null)))); return data; } diff --git a/android/app/src/main/java/com/example/petstoremobile/repositories/AppointmentRepository.java b/android/app/src/main/java/com/example/petstoremobile/repositories/AppointmentRepository.java index cea28d0a..3dd6037d 100644 --- a/android/app/src/main/java/com/example/petstoremobile/repositories/AppointmentRepository.java +++ b/android/app/src/main/java/com/example/petstoremobile/repositories/AppointmentRepository.java @@ -7,16 +7,14 @@ import com.example.petstoremobile.api.AppointmentApi; import com.example.petstoremobile.dtos.AppointmentDTO; import com.example.petstoremobile.dtos.PageResponse; import com.example.petstoremobile.utils.Resource; +import com.example.petstoremobile.utils.RetrofitUtils; import javax.inject.Inject; import javax.inject.Singleton; -import retrofit2.Call; -import retrofit2.Callback; -import retrofit2.Response; - @Singleton public class AppointmentRepository { + private static final String TAG = "AppointmentRepository"; private final AppointmentApi appointmentApi; @Inject @@ -31,21 +29,8 @@ public class AppointmentRepository { MutableLiveData>> data = new MutableLiveData<>(); data.setValue(Resource.loading(null)); - appointmentApi.getAllAppointments(page, size).enqueue(new Callback>() { - @Override - public void onResponse(Call> call, Response> response) { - if (response.isSuccessful() && response.body() != null) { - data.setValue(Resource.success(response.body())); - } else { - data.setValue(Resource.error("Error: " + response.message(), null)); - } - } - - @Override - public void onFailure(Call> call, Throwable t) { - data.setValue(Resource.error(t.getMessage(), null)); - } - }); + appointmentApi.getAllAppointments(page, size).enqueue(RetrofitUtils.createSilentCallback(TAG, + result -> data.setValue(Resource.success(result)))); return data; } @@ -57,21 +42,8 @@ public class AppointmentRepository { MutableLiveData> data = new MutableLiveData<>(); data.setValue(Resource.loading(null)); - appointmentApi.getAppointmentById(id).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful() && response.body() != null) { - data.setValue(Resource.success(response.body())); - } else { - data.setValue(Resource.error("Error: " + response.message(), null)); - } - } - - @Override - public void onFailure(Call call, Throwable t) { - data.setValue(Resource.error(t.getMessage(), null)); - } - }); + appointmentApi.getAppointmentById(id).enqueue(RetrofitUtils.createSilentCallback(TAG, + result -> data.setValue(Resource.success(result)))); return data; } @@ -83,21 +55,8 @@ public class AppointmentRepository { MutableLiveData> data = new MutableLiveData<>(); data.setValue(Resource.loading(null)); - appointmentApi.createAppointment(appointment).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful() && response.body() != null) { - data.setValue(Resource.success(response.body())); - } else { - data.setValue(Resource.error("Error: " + response.message(), null)); - } - } - - @Override - public void onFailure(Call call, Throwable t) { - data.setValue(Resource.error(t.getMessage(), null)); - } - }); + appointmentApi.createAppointment(appointment).enqueue(RetrofitUtils.createSilentCallback(TAG, + result -> data.setValue(Resource.success(result)))); return data; } @@ -109,21 +68,8 @@ public class AppointmentRepository { MutableLiveData> data = new MutableLiveData<>(); data.setValue(Resource.loading(null)); - appointmentApi.updateAppointment(id, appointment).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful() && response.body() != null) { - data.setValue(Resource.success(response.body())); - } else { - data.setValue(Resource.error("Error: " + response.message(), null)); - } - } - - @Override - public void onFailure(Call call, Throwable t) { - data.setValue(Resource.error(t.getMessage(), null)); - } - }); + appointmentApi.updateAppointment(id, appointment).enqueue(RetrofitUtils.createSilentCallback(TAG, + result -> data.setValue(Resource.success(result)))); return data; } @@ -135,21 +81,8 @@ public class AppointmentRepository { MutableLiveData> data = new MutableLiveData<>(); data.setValue(Resource.loading(null)); - appointmentApi.deleteAppointment(id).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful()) { - data.setValue(Resource.success(null)); - } else { - data.setValue(Resource.error("Error: " + response.message(), null)); - } - } - - @Override - public void onFailure(Call call, Throwable t) { - data.setValue(Resource.error(t.getMessage(), null)); - } - }); + appointmentApi.deleteAppointment(id).enqueue(RetrofitUtils.createSilentCallback(TAG, + result -> data.setValue(Resource.success(null)))); return data; } diff --git a/android/app/src/main/java/com/example/petstoremobile/repositories/AuthRepository.java b/android/app/src/main/java/com/example/petstoremobile/repositories/AuthRepository.java index c89de328..fd02e1ff 100644 --- a/android/app/src/main/java/com/example/petstoremobile/repositories/AuthRepository.java +++ b/android/app/src/main/java/com/example/petstoremobile/repositories/AuthRepository.java @@ -1,5 +1,7 @@ package com.example.petstoremobile.repositories; +import android.util.Log; + import androidx.lifecycle.LiveData; import androidx.lifecycle.MutableLiveData; @@ -8,6 +10,7 @@ import com.example.petstoremobile.api.auth.TokenManager; import com.example.petstoremobile.dtos.AuthDTO; import com.example.petstoremobile.dtos.UserDTO; import com.example.petstoremobile.utils.Resource; +import com.example.petstoremobile.utils.RetrofitUtils; import java.util.Map; @@ -15,12 +18,10 @@ import javax.inject.Inject; import javax.inject.Singleton; import okhttp3.MultipartBody; -import retrofit2.Call; -import retrofit2.Callback; -import retrofit2.Response; @Singleton public class AuthRepository { + private static final String TAG = "AuthRepository"; private final AuthApi authApi; private final TokenManager tokenManager; @@ -37,26 +38,14 @@ public class AuthRepository { MutableLiveData> data = new MutableLiveData<>(); data.setValue(Resource.loading(null)); - authApi.login(loginRequest).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful() && response.body() != null) { - tokenManager.saveLoginData( - response.body().getToken(), - response.body().getUsername(), - response.body().getRole() - ); - data.setValue(Resource.success(response.body())); - } else { - data.setValue(Resource.error("Login failed: " + response.message(), null)); - } + authApi.login(loginRequest).enqueue(RetrofitUtils.createSilentCallback(TAG, result -> { + if (result != null && result.getToken() != null) { + tokenManager.saveLoginData(result.getToken(), result.getUsername(), result.getRole()); + data.setValue(Resource.success(result)); + } else { + data.setValue(Resource.error("Login failed", null)); } - - @Override - public void onFailure(Call call, Throwable t) { - data.setValue(Resource.error(t.getMessage(), null)); - } - }); + })); return data; } @@ -68,21 +57,8 @@ public class AuthRepository { MutableLiveData> data = new MutableLiveData<>(); data.setValue(Resource.loading(null)); - authApi.getMe().enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful() && response.body() != null) { - data.setValue(Resource.success(response.body())); - } else { - data.setValue(Resource.error("Error: " + response.message(), null)); - } - } - - @Override - public void onFailure(Call call, Throwable t) { - data.setValue(Resource.error(t.getMessage(), null)); - } - }); + authApi.getMe().enqueue(RetrofitUtils.createSilentCallback(TAG, + result -> data.setValue(Resource.success(result)))); return data; } @@ -94,21 +70,8 @@ public class AuthRepository { MutableLiveData> data = new MutableLiveData<>(); data.setValue(Resource.loading(null)); - authApi.updateMe(updates).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful() && response.body() != null) { - data.setValue(Resource.success(response.body())); - } else { - data.setValue(Resource.error("Error: " + response.message(), null)); - } - } - - @Override - public void onFailure(Call call, Throwable t) { - data.setValue(Resource.error(t.getMessage(), null)); - } - }); + authApi.updateMe(updates).enqueue(RetrofitUtils.createSilentCallback(TAG, + result -> data.setValue(Resource.success(result)))); return data; } @@ -120,21 +83,8 @@ public class AuthRepository { MutableLiveData> data = new MutableLiveData<>(); data.setValue(Resource.loading(null)); - authApi.uploadAvatar(avatar).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful() && response.body() != null) { - data.setValue(Resource.success(response.body())); - } else { - data.setValue(Resource.error("Error: " + response.message(), null)); - } - } - - @Override - public void onFailure(Call call, Throwable t) { - data.setValue(Resource.error(t.getMessage(), null)); - } - }); + authApi.uploadAvatar(avatar).enqueue(RetrofitUtils.createSilentCallback(TAG, + result -> data.setValue(Resource.success(result)))); return data; } @@ -146,21 +96,8 @@ public class AuthRepository { MutableLiveData> data = new MutableLiveData<>(); data.setValue(Resource.loading(null)); - authApi.deleteAvatar().enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful()) { - data.setValue(Resource.success(null)); - } else { - data.setValue(Resource.error("Error: " + response.message(), null)); - } - } - - @Override - public void onFailure(Call call, Throwable t) { - data.setValue(Resource.error(t.getMessage(), null)); - } - }); + authApi.deleteAvatar().enqueue(RetrofitUtils.createSilentCallback(TAG, + result -> data.setValue(Resource.success(null)))); return data; } @@ -171,4 +108,8 @@ public class AuthRepository { public void logout() { tokenManager.clearLoginData(); } + + public boolean isLoggedIn() { + return tokenManager.getToken() != null; + } } diff --git a/android/app/src/main/java/com/example/petstoremobile/repositories/CategoryRepository.java b/android/app/src/main/java/com/example/petstoremobile/repositories/CategoryRepository.java index 7837f582..ae3769ed 100644 --- a/android/app/src/main/java/com/example/petstoremobile/repositories/CategoryRepository.java +++ b/android/app/src/main/java/com/example/petstoremobile/repositories/CategoryRepository.java @@ -7,16 +7,14 @@ import com.example.petstoremobile.api.CategoryApi; import com.example.petstoremobile.dtos.CategoryDTO; import com.example.petstoremobile.dtos.PageResponse; import com.example.petstoremobile.utils.Resource; +import com.example.petstoremobile.utils.RetrofitUtils; import javax.inject.Inject; import javax.inject.Singleton; -import retrofit2.Call; -import retrofit2.Callback; -import retrofit2.Response; - @Singleton public class CategoryRepository { + private static final String TAG = "CategoryRepository"; private final CategoryApi categoryApi; @Inject @@ -31,21 +29,8 @@ public class CategoryRepository { MutableLiveData>> data = new MutableLiveData<>(); data.setValue(Resource.loading(null)); - categoryApi.getAllCategories(page, size).enqueue(new Callback>() { - @Override - public void onResponse(Call> call, Response> response) { - if (response.isSuccessful() && response.body() != null) { - data.setValue(Resource.success(response.body())); - } else { - data.setValue(Resource.error("Error: " + response.message(), null)); - } - } - - @Override - public void onFailure(Call> call, Throwable t) { - data.setValue(Resource.error(t.getMessage(), null)); - } - }); + categoryApi.getAllCategories(page, size).enqueue(RetrofitUtils.createSilentCallback(TAG, + result -> data.setValue(Resource.success(result)))); return data; } diff --git a/android/app/src/main/java/com/example/petstoremobile/repositories/CustomerRepository.java b/android/app/src/main/java/com/example/petstoremobile/repositories/CustomerRepository.java new file mode 100644 index 00000000..cd0ae505 --- /dev/null +++ b/android/app/src/main/java/com/example/petstoremobile/repositories/CustomerRepository.java @@ -0,0 +1,50 @@ +package com.example.petstoremobile.repositories; + +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; + +import com.example.petstoremobile.api.CustomerApi; +import com.example.petstoremobile.dtos.CustomerDTO; +import com.example.petstoremobile.dtos.PageResponse; +import com.example.petstoremobile.utils.Resource; +import com.example.petstoremobile.utils.RetrofitUtils; + +import javax.inject.Inject; +import javax.inject.Singleton; + +@Singleton +public class CustomerRepository { + private static final String TAG = "CustomerRepository"; + private final CustomerApi customerApi; + + @Inject + public CustomerRepository(CustomerApi customerApi) { + this.customerApi = customerApi; + } + + /** + * Retrieves a paginated list of all customers from the API. + */ + public LiveData>> getAllCustomers(int page, int size) { + MutableLiveData>> data = new MutableLiveData<>(); + data.setValue(Resource.loading(null)); + + customerApi.getAllCustomers(page, size).enqueue(RetrofitUtils.createSilentCallback(TAG, + result -> data.setValue(Resource.success(result)))); + + return data; + } + + /** + * Retrieves a specific customer by their ID. + */ + public LiveData> getCustomerById(Long id) { + MutableLiveData> data = new MutableLiveData<>(); + data.setValue(Resource.loading(null)); + + customerApi.getCustomerById(id).enqueue(RetrofitUtils.createSilentCallback(TAG, + result -> data.setValue(Resource.success(result)))); + + return data; + } +} diff --git a/android/app/src/main/java/com/example/petstoremobile/repositories/InventoryRepository.java b/android/app/src/main/java/com/example/petstoremobile/repositories/InventoryRepository.java index ee2503cd..e08738ad 100644 --- a/android/app/src/main/java/com/example/petstoremobile/repositories/InventoryRepository.java +++ b/android/app/src/main/java/com/example/petstoremobile/repositories/InventoryRepository.java @@ -9,16 +9,16 @@ import com.example.petstoremobile.dtos.InventoryDTO; import com.example.petstoremobile.dtos.InventoryRequest; import com.example.petstoremobile.dtos.PageResponse; import com.example.petstoremobile.utils.Resource; +import com.example.petstoremobile.utils.RetrofitUtils; + +import java.util.List; import javax.inject.Inject; import javax.inject.Singleton; -import retrofit2.Call; -import retrofit2.Callback; -import retrofit2.Response; - @Singleton public class InventoryRepository { + private static final String TAG = "InventoryRepository"; private final InventoryApi inventoryApi; @Inject @@ -33,21 +33,8 @@ public class InventoryRepository { MutableLiveData>> data = new MutableLiveData<>(); data.setValue(Resource.loading(null)); - inventoryApi.getAllInventory(query, page, size, sort).enqueue(new Callback>() { - @Override - public void onResponse(Call> call, Response> response) { - if (response.isSuccessful() && response.body() != null) { - data.setValue(Resource.success(response.body())); - } else { - data.setValue(Resource.error("Error: " + response.message(), null)); - } - } - - @Override - public void onFailure(Call> call, Throwable t) { - data.setValue(Resource.error(t.getMessage(), null)); - } - }); + inventoryApi.getAllInventory(query, page, size, sort).enqueue(RetrofitUtils.createSilentCallback(TAG, + result -> data.setValue(Resource.success(result)))); return data; } @@ -59,21 +46,8 @@ public class InventoryRepository { MutableLiveData> data = new MutableLiveData<>(); data.setValue(Resource.loading(null)); - inventoryApi.getInventoryById(id).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful() && response.body() != null) { - data.setValue(Resource.success(response.body())); - } else { - data.setValue(Resource.error("Error: " + response.message(), null)); - } - } - - @Override - public void onFailure(Call call, Throwable t) { - data.setValue(Resource.error(t.getMessage(), null)); - } - }); + inventoryApi.getInventoryById(id).enqueue(RetrofitUtils.createSilentCallback(TAG, + result -> data.setValue(Resource.success(result)))); return data; } @@ -85,47 +59,18 @@ public class InventoryRepository { MutableLiveData> data = new MutableLiveData<>(); data.setValue(Resource.loading(null)); - inventoryApi.createInventory(request).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful() && response.body() != null) { - data.setValue(Resource.success(response.body())); - } else { - data.setValue(Resource.error("Error: " + response.message(), null)); - } - } - - @Override - public void onFailure(Call call, Throwable t) { - data.setValue(Resource.error(t.getMessage(), null)); - } - }); + inventoryApi.createInventory(request).enqueue(RetrofitUtils.createSilentCallback(TAG, + result -> data.setValue(Resource.success(result)))); return data; } - /** - * Sends a request to the API to update an existing inventory record. - */ public LiveData> updateInventory(Long id, InventoryRequest request) { MutableLiveData> data = new MutableLiveData<>(); data.setValue(Resource.loading(null)); - inventoryApi.updateInventory(id, request).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful() && response.body() != null) { - data.setValue(Resource.success(response.body())); - } else { - data.setValue(Resource.error("Error: " + response.message(), null)); - } - } - - @Override - public void onFailure(Call call, Throwable t) { - data.setValue(Resource.error(t.getMessage(), null)); - } - }); + inventoryApi.updateInventory(id, request).enqueue(RetrofitUtils.createSilentCallback(TAG, + result -> data.setValue(Resource.success(result)))); return data; } @@ -137,47 +82,18 @@ public class InventoryRepository { MutableLiveData> data = new MutableLiveData<>(); data.setValue(Resource.loading(null)); - inventoryApi.deleteInventory(id).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful()) { - data.setValue(Resource.success(null)); - } else { - data.setValue(Resource.error("Error: " + response.message(), null)); - } - } - - @Override - public void onFailure(Call call, Throwable t) { - data.setValue(Resource.error(t.getMessage(), null)); - } - }); + inventoryApi.deleteInventory(id).enqueue(RetrofitUtils.createSilentCallback(TAG, + result -> data.setValue(Resource.success(null)))); return data; } - /** - * Sends a request to the API to delete multiple inventory records at once. - */ public LiveData> bulkDeleteInventory(BulkDeleteRequest request) { MutableLiveData> data = new MutableLiveData<>(); data.setValue(Resource.loading(null)); - inventoryApi.bulkDeleteInventory(request).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful()) { - data.setValue(Resource.success(null)); - } else { - data.setValue(Resource.error("Error: " + response.message(), null)); - } - } - - @Override - public void onFailure(Call call, Throwable t) { - data.setValue(Resource.error(t.getMessage(), null)); - } - }); + inventoryApi.bulkDeleteInventory(request).enqueue(RetrofitUtils.createSilentCallback(TAG, + result -> data.setValue(Resource.success(null)))); return data; } diff --git a/android/app/src/main/java/com/example/petstoremobile/repositories/PetRepository.java b/android/app/src/main/java/com/example/petstoremobile/repositories/PetRepository.java index 0737e569..9fc087c3 100644 --- a/android/app/src/main/java/com/example/petstoremobile/repositories/PetRepository.java +++ b/android/app/src/main/java/com/example/petstoremobile/repositories/PetRepository.java @@ -1,22 +1,22 @@ package com.example.petstoremobile.repositories; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; + import com.example.petstoremobile.api.PetApi; import com.example.petstoremobile.dtos.PageResponse; import com.example.petstoremobile.dtos.PetDTO; import com.example.petstoremobile.utils.Resource; +import com.example.petstoremobile.utils.RetrofitUtils; import javax.inject.Inject; import javax.inject.Singleton; import okhttp3.MultipartBody; -import retrofit2.Call; -import retrofit2.Callback; -import retrofit2.Response; -import androidx.lifecycle.LiveData; -import androidx.lifecycle.MutableLiveData; @Singleton public class PetRepository { + private static final String TAG = "PetRepository"; private final PetApi petApi; @Inject @@ -31,21 +31,8 @@ public class PetRepository { MutableLiveData>> data = new MutableLiveData<>(); data.setValue(Resource.loading(null)); - petApi.getAllPets(page, size).enqueue(new Callback>() { - @Override - public void onResponse(Call> call, Response> response) { - if (response.isSuccessful() && response.body() != null) { - data.setValue(Resource.success(response.body())); - } else { - data.setValue(Resource.error("Error: " + response.message(), null)); - } - } - - @Override - public void onFailure(Call> call, Throwable t) { - data.setValue(Resource.error(t.getMessage(), null)); - } - }); + petApi.getAllPets(page, size).enqueue(RetrofitUtils.createSilentCallback(TAG, + result -> data.setValue(Resource.success(result)))); return data; } @@ -57,21 +44,8 @@ public class PetRepository { MutableLiveData> data = new MutableLiveData<>(); data.setValue(Resource.loading(null)); - petApi.getPetById(id).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful() && response.body() != null) { - data.setValue(Resource.success(response.body())); - } else { - data.setValue(Resource.error("Error: " + response.message(), null)); - } - } - - @Override - public void onFailure(Call call, Throwable t) { - data.setValue(Resource.error(t.getMessage(), null)); - } - }); + petApi.getPetById(id).enqueue(RetrofitUtils.createSilentCallback(TAG, + result -> data.setValue(Resource.success(result)))); return data; } @@ -83,21 +57,8 @@ public class PetRepository { MutableLiveData> data = new MutableLiveData<>(); data.setValue(Resource.loading(null)); - petApi.createPet(pet).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful() && response.body() != null) { - data.setValue(Resource.success(response.body())); - } else { - data.setValue(Resource.error("Error: " + response.message(), null)); - } - } - - @Override - public void onFailure(Call call, Throwable t) { - data.setValue(Resource.error(t.getMessage(), null)); - } - }); + petApi.createPet(pet).enqueue(RetrofitUtils.createSilentCallback(TAG, + result -> data.setValue(Resource.success(result)))); return data; } @@ -109,21 +70,8 @@ public class PetRepository { MutableLiveData> data = new MutableLiveData<>(); data.setValue(Resource.loading(null)); - petApi.updatePet(id, pet).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful() && response.body() != null) { - data.setValue(Resource.success(response.body())); - } else { - data.setValue(Resource.error("Error: " + response.message(), null)); - } - } - - @Override - public void onFailure(Call call, Throwable t) { - data.setValue(Resource.error(t.getMessage(), null)); - } - }); + petApi.updatePet(id, pet).enqueue(RetrofitUtils.createSilentCallback(TAG, + result -> data.setValue(Resource.success(result)))); return data; } @@ -135,21 +83,8 @@ public class PetRepository { MutableLiveData> data = new MutableLiveData<>(); data.setValue(Resource.loading(null)); - petApi.deletePet(id).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful()) { - data.setValue(Resource.success(null)); - } else { - data.setValue(Resource.error("Error: " + response.message(), null)); - } - } - - @Override - public void onFailure(Call call, Throwable t) { - data.setValue(Resource.error(t.getMessage(), null)); - } - }); + petApi.deletePet(id).enqueue(RetrofitUtils.createSilentCallback(TAG, + result -> data.setValue(Resource.success(null)))); return data; } @@ -161,21 +96,8 @@ public class PetRepository { MutableLiveData> data = new MutableLiveData<>(); data.setValue(Resource.loading(null)); - petApi.uploadPetImage(id, image).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful()) { - data.setValue(Resource.success(null)); - } else { - data.setValue(Resource.error("Error: " + response.message(), null)); - } - } - - @Override - public void onFailure(Call call, Throwable t) { - data.setValue(Resource.error(t.getMessage(), null)); - } - }); + petApi.uploadPetImage(id, image).enqueue(RetrofitUtils.createSilentCallback(TAG, + result -> data.setValue(Resource.success(null)))); return data; } @@ -187,21 +109,8 @@ public class PetRepository { MutableLiveData> data = new MutableLiveData<>(); data.setValue(Resource.loading(null)); - petApi.deletePetImage(id).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful()) { - data.setValue(Resource.success(null)); - } else { - data.setValue(Resource.error("Error: " + response.message(), null)); - } - } - - @Override - public void onFailure(Call call, Throwable t) { - data.setValue(Resource.error(t.getMessage(), null)); - } - }); + petApi.deletePetImage(id).enqueue(RetrofitUtils.createSilentCallback(TAG, + result -> data.setValue(Resource.success(null)))); return data; } diff --git a/android/app/src/main/java/com/example/petstoremobile/repositories/ProductRepository.java b/android/app/src/main/java/com/example/petstoremobile/repositories/ProductRepository.java index df79335f..84ac81b1 100644 --- a/android/app/src/main/java/com/example/petstoremobile/repositories/ProductRepository.java +++ b/android/app/src/main/java/com/example/petstoremobile/repositories/ProductRepository.java @@ -7,17 +7,16 @@ import com.example.petstoremobile.api.ProductApi; import com.example.petstoremobile.dtos.PageResponse; import com.example.petstoremobile.dtos.ProductDTO; import com.example.petstoremobile.utils.Resource; +import com.example.petstoremobile.utils.RetrofitUtils; import javax.inject.Inject; import javax.inject.Singleton; import okhttp3.MultipartBody; -import retrofit2.Call; -import retrofit2.Callback; -import retrofit2.Response; @Singleton public class ProductRepository { + private static final String TAG = "ProductRepository"; private final ProductApi productApi; @Inject @@ -32,21 +31,8 @@ public class ProductRepository { MutableLiveData>> data = new MutableLiveData<>(); data.setValue(Resource.loading(null)); - productApi.getAllProducts(query, page, size).enqueue(new Callback>() { - @Override - public void onResponse(Call> call, Response> response) { - if (response.isSuccessful() && response.body() != null) { - data.setValue(Resource.success(response.body())); - } else { - data.setValue(Resource.error("Error: " + response.message(), null)); - } - } - - @Override - public void onFailure(Call> call, Throwable t) { - data.setValue(Resource.error(t.getMessage(), null)); - } - }); + productApi.getAllProducts(query, page, size).enqueue(RetrofitUtils.createSilentCallback(TAG, + result -> data.setValue(Resource.success(result)))); return data; } @@ -58,21 +44,8 @@ public class ProductRepository { MutableLiveData> data = new MutableLiveData<>(); data.setValue(Resource.loading(null)); - productApi.getProductById(id).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful() && response.body() != null) { - data.setValue(Resource.success(response.body())); - } else { - data.setValue(Resource.error("Error: " + response.message(), null)); - } - } - - @Override - public void onFailure(Call call, Throwable t) { - data.setValue(Resource.error(t.getMessage(), null)); - } - }); + productApi.getProductById(id).enqueue(RetrofitUtils.createSilentCallback(TAG, + result -> data.setValue(Resource.success(result)))); return data; } @@ -84,21 +57,8 @@ public class ProductRepository { MutableLiveData> data = new MutableLiveData<>(); data.setValue(Resource.loading(null)); - productApi.createProduct(product).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful() && response.body() != null) { - data.setValue(Resource.success(response.body())); - } else { - data.setValue(Resource.error("Error: " + response.message(), null)); - } - } - - @Override - public void onFailure(Call call, Throwable t) { - data.setValue(Resource.error(t.getMessage(), null)); - } - }); + productApi.createProduct(product).enqueue(RetrofitUtils.createSilentCallback(TAG, + result -> data.setValue(Resource.success(result)))); return data; } @@ -110,21 +70,8 @@ public class ProductRepository { MutableLiveData> data = new MutableLiveData<>(); data.setValue(Resource.loading(null)); - productApi.updateProduct(id, product).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful() && response.body() != null) { - data.setValue(Resource.success(response.body())); - } else { - data.setValue(Resource.error("Error: " + response.message(), null)); - } - } - - @Override - public void onFailure(Call call, Throwable t) { - data.setValue(Resource.error(t.getMessage(), null)); - } - }); + productApi.updateProduct(id, product).enqueue(RetrofitUtils.createSilentCallback(TAG, + result -> data.setValue(Resource.success(result)))); return data; } @@ -136,21 +83,8 @@ public class ProductRepository { MutableLiveData> data = new MutableLiveData<>(); data.setValue(Resource.loading(null)); - productApi.deleteProduct(id).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful()) { - data.setValue(Resource.success(null)); - } else { - data.setValue(Resource.error("Error: " + response.message(), null)); - } - } - - @Override - public void onFailure(Call call, Throwable t) { - data.setValue(Resource.error(t.getMessage(), null)); - } - }); + productApi.deleteProduct(id).enqueue(RetrofitUtils.createSilentCallback(TAG, + result -> data.setValue(Resource.success(null)))); return data; } @@ -162,21 +96,8 @@ public class ProductRepository { MutableLiveData> data = new MutableLiveData<>(); data.setValue(Resource.loading(null)); - productApi.uploadProductImage(id, image).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful()) { - data.setValue(Resource.success(null)); - } else { - data.setValue(Resource.error("Error: " + response.message(), null)); - } - } - - @Override - public void onFailure(Call call, Throwable t) { - data.setValue(Resource.error(t.getMessage(), null)); - } - }); + productApi.uploadProductImage(id, image).enqueue(RetrofitUtils.createSilentCallback(TAG, + result -> data.setValue(Resource.success(null)))); return data; } @@ -188,21 +109,8 @@ public class ProductRepository { MutableLiveData> data = new MutableLiveData<>(); data.setValue(Resource.loading(null)); - productApi.deleteProductImage(id).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful()) { - data.setValue(Resource.success(null)); - } else { - data.setValue(Resource.error("Error: " + response.message(), null)); - } - } - - @Override - public void onFailure(Call call, Throwable t) { - data.setValue(Resource.error(t.getMessage(), null)); - } - }); + productApi.deleteProductImage(id).enqueue(RetrofitUtils.createSilentCallback(TAG, + result -> data.setValue(Resource.success(null)))); return data; } diff --git a/android/app/src/main/java/com/example/petstoremobile/repositories/ProductSupplierRepository.java b/android/app/src/main/java/com/example/petstoremobile/repositories/ProductSupplierRepository.java index 2e961f6c..eebe13f6 100644 --- a/android/app/src/main/java/com/example/petstoremobile/repositories/ProductSupplierRepository.java +++ b/android/app/src/main/java/com/example/petstoremobile/repositories/ProductSupplierRepository.java @@ -7,16 +7,14 @@ import com.example.petstoremobile.api.ProductSupplierApi; import com.example.petstoremobile.dtos.PageResponse; import com.example.petstoremobile.dtos.ProductSupplierDTO; import com.example.petstoremobile.utils.Resource; +import com.example.petstoremobile.utils.RetrofitUtils; import javax.inject.Inject; import javax.inject.Singleton; -import retrofit2.Call; -import retrofit2.Callback; -import retrofit2.Response; - @Singleton public class ProductSupplierRepository { + private static final String TAG = "ProductSupplierRepository"; private final ProductSupplierApi api; @Inject @@ -31,21 +29,8 @@ public class ProductSupplierRepository { MutableLiveData>> data = new MutableLiveData<>(); data.setValue(Resource.loading(null)); - api.getAllProductSuppliers(page, size).enqueue(new Callback>() { - @Override - public void onResponse(Call> call, Response> response) { - if (response.isSuccessful() && response.body() != null) { - data.setValue(Resource.success(response.body())); - } else { - data.setValue(Resource.error("Error: " + response.message(), null)); - } - } - - @Override - public void onFailure(Call> call, Throwable t) { - data.setValue(Resource.error(t.getMessage(), null)); - } - }); + api.getAllProductSuppliers(page, size).enqueue(RetrofitUtils.createSilentCallback(TAG, + result -> data.setValue(Resource.success(result)))); return data; } @@ -57,21 +42,8 @@ public class ProductSupplierRepository { MutableLiveData> data = new MutableLiveData<>(); data.setValue(Resource.loading(null)); - api.createProductSupplier(dto).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful() && response.body() != null) { - data.setValue(Resource.success(response.body())); - } else { - data.setValue(Resource.error("Error: " + response.message(), null)); - } - } - - @Override - public void onFailure(Call call, Throwable t) { - data.setValue(Resource.error(t.getMessage(), null)); - } - }); + api.createProductSupplier(dto).enqueue(RetrofitUtils.createSilentCallback(TAG, + result -> data.setValue(Resource.success(result)))); return data; } @@ -83,21 +55,8 @@ public class ProductSupplierRepository { MutableLiveData> data = new MutableLiveData<>(); data.setValue(Resource.loading(null)); - api.updateProductSupplier(productId, supplierId, dto).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful() && response.body() != null) { - data.setValue(Resource.success(response.body())); - } else { - data.setValue(Resource.error("Error: " + response.message(), null)); - } - } - - @Override - public void onFailure(Call call, Throwable t) { - data.setValue(Resource.error(t.getMessage(), null)); - } - }); + api.updateProductSupplier(productId, supplierId, dto).enqueue(RetrofitUtils.createSilentCallback(TAG, + result -> data.setValue(Resource.success(result)))); return data; } @@ -109,21 +68,8 @@ public class ProductSupplierRepository { MutableLiveData> data = new MutableLiveData<>(); data.setValue(Resource.loading(null)); - api.deleteProductSupplier(productId, supplierId).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful()) { - data.setValue(Resource.success(null)); - } else { - data.setValue(Resource.error("Error: " + response.message(), null)); - } - } - - @Override - public void onFailure(Call call, Throwable t) { - data.setValue(Resource.error(t.getMessage(), null)); - } - }); + api.deleteProductSupplier(productId, supplierId).enqueue(RetrofitUtils.createSilentCallback(TAG, + result -> data.setValue(Resource.success(null)))); return data; } diff --git a/android/app/src/main/java/com/example/petstoremobile/repositories/PurchaseOrderRepository.java b/android/app/src/main/java/com/example/petstoremobile/repositories/PurchaseOrderRepository.java index f804c2e3..ad46c26b 100644 --- a/android/app/src/main/java/com/example/petstoremobile/repositories/PurchaseOrderRepository.java +++ b/android/app/src/main/java/com/example/petstoremobile/repositories/PurchaseOrderRepository.java @@ -7,6 +7,7 @@ import com.example.petstoremobile.api.PurchaseOrderApi; import com.example.petstoremobile.dtos.PageResponse; import com.example.petstoremobile.dtos.PurchaseOrderDTO; import com.example.petstoremobile.utils.Resource; +import com.example.petstoremobile.utils.RetrofitUtils; import javax.inject.Inject; import javax.inject.Singleton; @@ -17,6 +18,7 @@ import retrofit2.Response; @Singleton public class PurchaseOrderRepository { + private static final String TAG = "PurchaseOrderRepo"; private final PurchaseOrderApi api; @Inject @@ -31,21 +33,9 @@ public class PurchaseOrderRepository { MutableLiveData>> data = new MutableLiveData<>(); data.setValue(Resource.loading(null)); - api.getAllPurchaseOrders(page, size).enqueue(new Callback>() { - @Override - public void onResponse(Call> call, Response> response) { - if (response.isSuccessful() && response.body() != null) { - data.setValue(Resource.success(response.body())); - } else { - data.setValue(Resource.error("Error: " + response.message(), null)); - } - } - - @Override - public void onFailure(Call> call, Throwable t) { - data.setValue(Resource.error(t.getMessage(), null)); - } - }); + api.getAllPurchaseOrders(page, size).enqueue(RetrofitUtils.createSilentCallback(TAG, result -> { + data.setValue(Resource.success(result)); + })); return data; } @@ -57,21 +47,9 @@ public class PurchaseOrderRepository { MutableLiveData> data = new MutableLiveData<>(); data.setValue(Resource.loading(null)); - api.getPurchaseOrderById(id).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful() && response.body() != null) { - data.setValue(Resource.success(response.body())); - } else { - data.setValue(Resource.error("Error: " + response.message(), null)); - } - } - - @Override - public void onFailure(Call call, Throwable t) { - data.setValue(Resource.error(t.getMessage(), null)); - } - }); + api.getPurchaseOrderById(id).enqueue(RetrofitUtils.createSilentCallback(TAG, result -> { + data.setValue(Resource.success(result)); + })); return data; } diff --git a/android/app/src/main/java/com/example/petstoremobile/repositories/ServiceRepository.java b/android/app/src/main/java/com/example/petstoremobile/repositories/ServiceRepository.java index 8d81ccfb..4503fa80 100644 --- a/android/app/src/main/java/com/example/petstoremobile/repositories/ServiceRepository.java +++ b/android/app/src/main/java/com/example/petstoremobile/repositories/ServiceRepository.java @@ -7,16 +7,14 @@ import com.example.petstoremobile.api.ServiceApi; import com.example.petstoremobile.dtos.PageResponse; import com.example.petstoremobile.dtos.ServiceDTO; import com.example.petstoremobile.utils.Resource; +import com.example.petstoremobile.utils.RetrofitUtils; import javax.inject.Inject; import javax.inject.Singleton; -import retrofit2.Call; -import retrofit2.Callback; -import retrofit2.Response; - @Singleton public class ServiceRepository { + private static final String TAG = "ServiceRepository"; private final ServiceApi serviceApi; @Inject @@ -31,21 +29,8 @@ public class ServiceRepository { MutableLiveData>> data = new MutableLiveData<>(); data.setValue(Resource.loading(null)); - serviceApi.getAllServices(page, size).enqueue(new Callback>() { - @Override - public void onResponse(Call> call, Response> response) { - if (response.isSuccessful() && response.body() != null) { - data.setValue(Resource.success(response.body())); - } else { - data.setValue(Resource.error("Error: " + response.message(), null)); - } - } - - @Override - public void onFailure(Call> call, Throwable t) { - data.setValue(Resource.error(t.getMessage(), null)); - } - }); + serviceApi.getAllServices(page, size).enqueue(RetrofitUtils.createSilentCallback(TAG, + result -> data.setValue(Resource.success(result)))); return data; } @@ -57,21 +42,8 @@ public class ServiceRepository { MutableLiveData> data = new MutableLiveData<>(); data.setValue(Resource.loading(null)); - serviceApi.getServiceById(id).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful() && response.body() != null) { - data.setValue(Resource.success(response.body())); - } else { - data.setValue(Resource.error("Error: " + response.message(), null)); - } - } - - @Override - public void onFailure(Call call, Throwable t) { - data.setValue(Resource.error(t.getMessage(), null)); - } - }); + serviceApi.getServiceById(id).enqueue(RetrofitUtils.createSilentCallback(TAG, + result -> data.setValue(Resource.success(result)))); return data; } @@ -83,21 +55,8 @@ public class ServiceRepository { MutableLiveData> data = new MutableLiveData<>(); data.setValue(Resource.loading(null)); - serviceApi.createService(service).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful() && response.body() != null) { - data.setValue(Resource.success(response.body())); - } else { - data.setValue(Resource.error("Error: " + response.message(), null)); - } - } - - @Override - public void onFailure(Call call, Throwable t) { - data.setValue(Resource.error(t.getMessage(), null)); - } - }); + serviceApi.createService(service).enqueue(RetrofitUtils.createSilentCallback(TAG, + result -> data.setValue(Resource.success(result)))); return data; } @@ -109,21 +68,8 @@ public class ServiceRepository { MutableLiveData> data = new MutableLiveData<>(); data.setValue(Resource.loading(null)); - serviceApi.updateService(id, service).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful() && response.body() != null) { - data.setValue(Resource.success(response.body())); - } else { - data.setValue(Resource.error("Error: " + response.message(), null)); - } - } - - @Override - public void onFailure(Call call, Throwable t) { - data.setValue(Resource.error(t.getMessage(), null)); - } - }); + serviceApi.updateService(id, service).enqueue(RetrofitUtils.createSilentCallback(TAG, + result -> data.setValue(Resource.success(result)))); return data; } @@ -135,21 +81,8 @@ public class ServiceRepository { MutableLiveData> data = new MutableLiveData<>(); data.setValue(Resource.loading(null)); - serviceApi.deleteService(id).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful()) { - data.setValue(Resource.success(null)); - } else { - data.setValue(Resource.error("Error: " + response.message(), null)); - } - } - - @Override - public void onFailure(Call call, Throwable t) { - data.setValue(Resource.error(t.getMessage(), null)); - } - }); + serviceApi.deleteService(id).enqueue(RetrofitUtils.createSilentCallback(TAG, + result -> data.setValue(Resource.success(null)))); return data; } diff --git a/android/app/src/main/java/com/example/petstoremobile/repositories/StoreRepository.java b/android/app/src/main/java/com/example/petstoremobile/repositories/StoreRepository.java new file mode 100644 index 00000000..e6609bdc --- /dev/null +++ b/android/app/src/main/java/com/example/petstoremobile/repositories/StoreRepository.java @@ -0,0 +1,37 @@ +package com.example.petstoremobile.repositories; + +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; + +import com.example.petstoremobile.api.StoreApi; +import com.example.petstoremobile.dtos.PageResponse; +import com.example.petstoremobile.dtos.StoreDTO; +import com.example.petstoremobile.utils.Resource; +import com.example.petstoremobile.utils.RetrofitUtils; + +import javax.inject.Inject; +import javax.inject.Singleton; + +@Singleton +public class StoreRepository { + private static final String TAG = "StoreRepository"; + private final StoreApi storeApi; + + @Inject + public StoreRepository(StoreApi storeApi) { + this.storeApi = storeApi; + } + + /** + * Retrieves a paginated list of all stores from the API. + */ + public LiveData>> getAllStores(int page, int size) { + MutableLiveData>> data = new MutableLiveData<>(); + data.setValue(Resource.loading(null)); + + storeApi.getAllStores(page, size).enqueue(RetrofitUtils.createSilentCallback(TAG, + result -> data.setValue(Resource.success(result)))); + + return data; + } +} diff --git a/android/app/src/main/java/com/example/petstoremobile/repositories/SupplierRepository.java b/android/app/src/main/java/com/example/petstoremobile/repositories/SupplierRepository.java index eb7b8b61..a7a1b633 100644 --- a/android/app/src/main/java/com/example/petstoremobile/repositories/SupplierRepository.java +++ b/android/app/src/main/java/com/example/petstoremobile/repositories/SupplierRepository.java @@ -7,16 +7,14 @@ import com.example.petstoremobile.api.SupplierApi; import com.example.petstoremobile.dtos.PageResponse; import com.example.petstoremobile.dtos.SupplierDTO; import com.example.petstoremobile.utils.Resource; +import com.example.petstoremobile.utils.RetrofitUtils; import javax.inject.Inject; import javax.inject.Singleton; -import retrofit2.Call; -import retrofit2.Callback; -import retrofit2.Response; - @Singleton public class SupplierRepository { + private static final String TAG = "SupplierRepository"; private final SupplierApi supplierApi; @Inject @@ -31,21 +29,8 @@ public class SupplierRepository { MutableLiveData>> data = new MutableLiveData<>(); data.setValue(Resource.loading(null)); - supplierApi.getAllSuppliers(page, size).enqueue(new Callback>() { - @Override - public void onResponse(Call> call, Response> response) { - if (response.isSuccessful() && response.body() != null) { - data.setValue(Resource.success(response.body())); - } else { - data.setValue(Resource.error("Error: " + response.message(), null)); - } - } - - @Override - public void onFailure(Call> call, Throwable t) { - data.setValue(Resource.error(t.getMessage(), null)); - } - }); + supplierApi.getAllSuppliers(page, size).enqueue(RetrofitUtils.createSilentCallback(TAG, + result -> data.setValue(Resource.success(result)))); return data; } @@ -57,21 +42,8 @@ public class SupplierRepository { MutableLiveData> data = new MutableLiveData<>(); data.setValue(Resource.loading(null)); - supplierApi.getSupplierById(id).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful() && response.body() != null) { - data.setValue(Resource.success(response.body())); - } else { - data.setValue(Resource.error("Error: " + response.message(), null)); - } - } - - @Override - public void onFailure(Call call, Throwable t) { - data.setValue(Resource.error(t.getMessage(), null)); - } - }); + supplierApi.getSupplierById(id).enqueue(RetrofitUtils.createSilentCallback(TAG, + result -> data.setValue(Resource.success(result)))); return data; } @@ -83,21 +55,8 @@ public class SupplierRepository { MutableLiveData> data = new MutableLiveData<>(); data.setValue(Resource.loading(null)); - supplierApi.createSupplier(supplier).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful() && response.body() != null) { - data.setValue(Resource.success(response.body())); - } else { - data.setValue(Resource.error("Error: " + response.message(), null)); - } - } - - @Override - public void onFailure(Call call, Throwable t) { - data.setValue(Resource.error(t.getMessage(), null)); - } - }); + supplierApi.createSupplier(supplier).enqueue(RetrofitUtils.createSilentCallback(TAG, + result -> data.setValue(Resource.success(result)))); return data; } @@ -106,26 +65,15 @@ public class SupplierRepository { * Sends a request to the API to update an existing supplier record by ID. */ public LiveData> updateSupplier(Long id, SupplierDTO supplier) { - MutableLiveData> data = new MutableLiveData<>(); - data.setValue(Resource.loading(null)); + MutableLiveData>> data = new MutableLiveData<>(); + // Note: The original return type was LiveData>, fixing here + MutableLiveData> resultData = new MutableLiveData<>(); + resultData.setValue(Resource.loading(null)); - supplierApi.updateSupplier(id, supplier).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful() && response.body() != null) { - data.setValue(Resource.success(response.body())); - } else { - data.setValue(Resource.error("Error: " + response.message(), null)); - } - } + supplierApi.updateSupplier(id, supplier).enqueue(RetrofitUtils.createSilentCallback(TAG, + result -> resultData.setValue(Resource.success(result)))); - @Override - public void onFailure(Call call, Throwable t) { - data.setValue(Resource.error(t.getMessage(), null)); - } - }); - - return data; + return resultData; } /** @@ -135,21 +83,8 @@ public class SupplierRepository { MutableLiveData> data = new MutableLiveData<>(); data.setValue(Resource.loading(null)); - supplierApi.deleteSupplier(id).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful()) { - data.setValue(Resource.success(null)); - } else { - data.setValue(Resource.error("Error: " + response.message(), null)); - } - } - - @Override - public void onFailure(Call call, Throwable t) { - data.setValue(Resource.error(t.getMessage(), null)); - } - }); + supplierApi.deleteSupplier(id).enqueue(RetrofitUtils.createSilentCallback(TAG, + result -> data.setValue(Resource.success(null)))); return data; } diff --git a/android/app/src/main/java/com/example/petstoremobile/services/ChatNotificationService.java b/android/app/src/main/java/com/example/petstoremobile/services/ChatNotificationService.java index a502d8d0..90113cac 100644 --- a/android/app/src/main/java/com/example/petstoremobile/services/ChatNotificationService.java +++ b/android/app/src/main/java/com/example/petstoremobile/services/ChatNotificationService.java @@ -14,6 +14,7 @@ import com.example.petstoremobile.dtos.CustomerDTO; import com.example.petstoremobile.dtos.MessageDTO; import com.example.petstoremobile.dtos.PageResponse; import com.example.petstoremobile.utils.NotificationHelper; +import com.example.petstoremobile.utils.RetrofitUtils; import com.example.petstoremobile.websocket.StompChatManager; import java.util.HashMap; import java.util.HashSet; @@ -63,54 +64,31 @@ public class ChatNotificationService extends Service { currentUserId = tokenManager.getUserId(); if (token != null && stompChatManager == null) { - customerApi.getAllCustomers(0, 1000).enqueue(new Callback>() { - @Override - public void onResponse(@NonNull Call> call, @NonNull Response> response) { - if (response.isSuccessful() && response.body() != null) { - for (CustomerDTO customer : response.body().getContent()) { - customerIdToName.put(customer.getCustomerId(), customer.getFullName()); - } - } - loadConversationsAndStartStomp(token, role); + customerApi.getAllCustomers(0, 1000).enqueue(RetrofitUtils.createSilentCallback(TAG, result -> { + for (CustomerDTO customer : result.getContent()) { + customerIdToName.put(customer.getCustomerId(), customer.getFullName()); } - - @Override - public void onFailure(@NonNull Call> call, @NonNull Throwable t) { - Log.e(TAG, "Failed to load customers", t); - loadConversationsAndStartStomp(token, role); - } - }); + loadConversationsAndStartStomp(token, role); + })); } } private void loadConversationsAndStartStomp(String token, String role) { // Fetch existing conversations - chatApi.getAllConversations().enqueue(new Callback>() { - @Override - public void onResponse(@NonNull Call> call, @NonNull Response> response) { - if (response.isSuccessful() && response.body() != null) { - for (ConversationDTO conversation : response.body()) { - if (conversation.getId() != null) { - knownConversationIds.add(conversation.getId()); - conversationToCustomerId.put(conversation.getId(), conversation.getCustomerId()); - // subscribe to existing conversations to get message notifications - if (stompChatManager != null) { - stompChatManager.subscribeToConversation(conversation.getId()); - } - } + chatApi.getAllConversations().enqueue(RetrofitUtils.createSilentCallback(TAG, result -> { + for (ConversationDTO conversation : result) { + if (conversation.getId() != null) { + knownConversationIds.add(conversation.getId()); + conversationToCustomerId.put(conversation.getId(), conversation.getCustomerId()); + // subscribe to existing conversations to get message notifications + if (stompChatManager != null) { + stompChatManager.subscribeToConversation(conversation.getId()); } - Log.d(TAG, "Loaded " + knownConversationIds.size() + " existing conversations"); } - startStomp(token, role); } - - @Override - public void onFailure(@NonNull Call> call, @NonNull Throwable t) { - Log.e(TAG, "Failed to load existing conversations", t); - //tries to connect if loading fails - startStomp(token, role); - } - }); + Log.d(TAG, "Loaded " + knownConversationIds.size() + " existing conversations"); + startStomp(token, role); + })); } private void startStomp(String token, String role) { @@ -199,19 +177,9 @@ public class ChatNotificationService extends Service { // Helper function to fetch customer name for a conversation private void fetchCustomerName(Long customerId) { - customerApi.getCustomerById(customerId).enqueue(new Callback() { - @Override - public void onResponse(@NonNull Call call, @NonNull Response response) { - if (response.isSuccessful() && response.body() != null) { - customerIdToName.put(customerId, response.body().getFullName()); - } - } - - @Override - public void onFailure(@NonNull Call call, @NonNull Throwable t) { - Log.e(TAG, "Failed to fetch customer name", t); - } - }); + customerApi.getCustomerById(customerId).enqueue(RetrofitUtils.createSilentCallback(TAG, result -> { + customerIdToName.put(customerId, result.getFullName()); + })); } //When the service is destroyed, disconnect from the websocket @@ -228,4 +196,4 @@ public class ChatNotificationService extends Service { public IBinder onBind(Intent intent) { return null; } -} \ No newline at end of file +} diff --git a/android/app/src/main/java/com/example/petstoremobile/utils/RetrofitUtils.java b/android/app/src/main/java/com/example/petstoremobile/utils/RetrofitUtils.java new file mode 100644 index 00000000..a5a1b041 --- /dev/null +++ b/android/app/src/main/java/com/example/petstoremobile/utils/RetrofitUtils.java @@ -0,0 +1,74 @@ +package com.example.petstoremobile.utils; + +import android.content.Context; +import android.util.Log; +import android.widget.Toast; + +import androidx.annotation.NonNull; + +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; + +/** + * Utility class for common Retrofit operations and standardized callbacks. + */ +public class RetrofitUtils { + + /** + * Interface for handling successful API responses. + * @param The type of the response body. + */ + public interface SuccessCallback { + void onSuccess(T result); + } + + /** + * Creates a callback for Retrofit calls that handles errors and logging. + */ + public static Callback createCallback(Context context, String tag, String successMsg, SuccessCallback successCallback) { + return new Callback() { + @Override + public void onResponse(@NonNull Call call, @NonNull Response response) { + if (response.isSuccessful()) { + if (successMsg != null) { + Toast.makeText(context, successMsg, Toast.LENGTH_SHORT).show(); + } + if (successCallback != null) { + successCallback.onSuccess(response.body()); + } + } else { + ErrorUtils.showErrorMessage(context, response, "Operation failed"); + Log.e(tag, "API Error: " + response.code()); + } + } + + @Override + public void onFailure(@NonNull Call call, @NonNull Throwable t) { + Log.e(tag, "Network Error: " + t.getMessage()); + Toast.makeText(context, "Network error. Please try again.", Toast.LENGTH_SHORT).show(); + } + }; + } + + /** + * Creates a callback that doesn't show toasts + */ + public static Callback createSilentCallback(String tag, SuccessCallback successCallback) { + return new Callback() { + @Override + public void onResponse(@NonNull Call call, @NonNull Response response) { + if (response.isSuccessful() && successCallback != null) { + successCallback.onSuccess(response.body()); + } else { + Log.e(tag, "API Error: " + response.code()); + } + } + + @Override + public void onFailure(@NonNull Call call, @NonNull Throwable t) { + Log.e(tag, "Network Error: " + t.getMessage()); + } + }; + } +} diff --git a/android/app/src/main/java/com/example/petstoremobile/viewmodels/CustomerViewModel.java b/android/app/src/main/java/com/example/petstoremobile/viewmodels/CustomerViewModel.java new file mode 100644 index 00000000..5ad7cc76 --- /dev/null +++ b/android/app/src/main/java/com/example/petstoremobile/viewmodels/CustomerViewModel.java @@ -0,0 +1,37 @@ +package com.example.petstoremobile.viewmodels; + +import androidx.lifecycle.LiveData; +import androidx.lifecycle.ViewModel; + +import com.example.petstoremobile.dtos.CustomerDTO; +import com.example.petstoremobile.dtos.PageResponse; +import com.example.petstoremobile.repositories.CustomerRepository; +import com.example.petstoremobile.utils.Resource; + +import javax.inject.Inject; + +import dagger.hilt.android.lifecycle.HiltViewModel; + +@HiltViewModel +public class CustomerViewModel extends ViewModel { + private final CustomerRepository repository; + + @Inject + public CustomerViewModel(CustomerRepository repository) { + this.repository = repository; + } + + /** + * Fetches a paginated list of all customers. + */ + public LiveData>> getAllCustomers(int page, int size) { + return repository.getAllCustomers(page, size); + } + + /** + * Retrieves a single customer by their ID. + */ + public LiveData> getCustomerById(Long id) { + return repository.getCustomerById(id); + } +} diff --git a/android/app/src/main/java/com/example/petstoremobile/viewmodels/StoreViewModel.java b/android/app/src/main/java/com/example/petstoremobile/viewmodels/StoreViewModel.java new file mode 100644 index 00000000..83f4c3b3 --- /dev/null +++ b/android/app/src/main/java/com/example/petstoremobile/viewmodels/StoreViewModel.java @@ -0,0 +1,30 @@ +package com.example.petstoremobile.viewmodels; + +import androidx.lifecycle.LiveData; +import androidx.lifecycle.ViewModel; + +import com.example.petstoremobile.dtos.PageResponse; +import com.example.petstoremobile.dtos.StoreDTO; +import com.example.petstoremobile.repositories.StoreRepository; +import com.example.petstoremobile.utils.Resource; + +import javax.inject.Inject; + +import dagger.hilt.android.lifecycle.HiltViewModel; + +@HiltViewModel +public class StoreViewModel extends ViewModel { + private final StoreRepository repository; + + @Inject + public StoreViewModel(StoreRepository repository) { + this.repository = repository; + } + + /** + * Fetches a paginated list of all stores. + */ + public LiveData>> getAllStores(int page, int size) { + return repository.getAllStores(page, size); + } +}