Refactored more of the project to MVVM and created helper class RetrofitUtil to reduce redundent code

This commit is contained in:
Alex
2026-04-05 21:27:32 -06:00
parent 693829ce42
commit 38a0242264
28 changed files with 855 additions and 1669 deletions

View File

@@ -80,6 +80,7 @@ public class HomeActivity extends AppCompatActivity {
@Override @Override
protected void onNewIntent(Intent intent) { protected void onNewIntent(Intent intent) {
super.onNewIntent(intent); super.onNewIntent(intent);
setIntent(intent); // Set the new intent so fragments can access updated extras
handleIntent(intent); handleIntent(intent);
} }
@@ -88,13 +89,9 @@ public class HomeActivity extends AppCompatActivity {
*/ */
private void handleIntent(Intent intent) { private void handleIntent(Intent intent) {
if (intent != null && "chat".equals(intent.getStringExtra("navigate_to"))) { if (intent != null && "chat".equals(intent.getStringExtra("navigate_to"))) {
Bundle args = new Bundle(); if (bottomNav != null) {
if (intent.hasExtra("conversation_id")) { // Navigate by selecting the bottom nav item.
args.putLong("conversation_id", intent.getLongExtra("conversation_id", -1)); bottomNav.setSelectedItemId(R.id.nav_chat);
}
// Use NavController to navigate
if (navController != null) {
navController.navigate(R.id.nav_chat, args);
} }
} }
} }

View File

@@ -34,6 +34,7 @@ import com.example.petstoremobile.dtos.SendMessageRequest;
import com.example.petstoremobile.models.Chat; import com.example.petstoremobile.models.Chat;
import com.example.petstoremobile.models.Message; import com.example.petstoremobile.models.Message;
import com.example.petstoremobile.services.ChatNotificationService; import com.example.petstoremobile.services.ChatNotificationService;
import com.example.petstoremobile.utils.RetrofitUtils;
import com.example.petstoremobile.websocket.StompChatManager; import com.example.petstoremobile.websocket.StompChatManager;
import java.util.*; import java.util.*;
@@ -202,6 +203,10 @@ public class ChatFragment extends Fragment implements ChatAdapter.OnChatClickLis
if (getArguments() != null && getArguments().containsKey("conversation_id")) { if (getArguments() != null && getArguments().containsKey("conversation_id")) {
activeConversationId = getArguments().getLong("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(); 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. * Fetches a list of customers from the API to display customer names for the chat list.
*/ */
private void loadCustomers() { private void loadCustomers() {
customerApi.getAllCustomers(0, 100).enqueue(new Callback<PageResponse<CustomerDTO>>() { customerApi.getAllCustomers(0, 100).enqueue(RetrofitUtils.createSilentCallback(TAG, result -> {
@Override for (CustomerDTO c : result.getContent()) {
public void onResponse(@NonNull Call<PageResponse<CustomerDTO>> call, customerNames.put(c.getCustomerId(), c.getFullName());
@NonNull Response<PageResponse<CustomerDTO>> response) {
if (response.isSuccessful() && response.body() != null) {
for (CustomerDTO c : response.body().getContent()) {
customerNames.put(c.getCustomerId(), c.getFullName());
}
}
loadConversations();
} }
loadConversations();
@Override }));
public void onFailure(@NonNull Call<PageResponse<CustomerDTO>> call,
@NonNull Throwable t) {
loadConversations();
}
});
} }
/** /**
* Retrieves all conversations for the current user and populates the chat drawer. * Retrieves all conversations for the current user and populates the chat drawer.
*/ */
private void loadConversations() { private void loadConversations() {
chatApi.getAllConversations().enqueue(new Callback<List<ConversationDTO>>() { chatApi.getAllConversations().enqueue(RetrofitUtils.createSilentCallback(TAG, result -> {
@Override chatList.clear();
public void onResponse(@NonNull Call<List<ConversationDTO>> call, List<Chat> loaded = result.stream()
@NonNull Response<List<ConversationDTO>> response) { .map(dto -> {
if (response.isSuccessful() && response.body() != null) { String name = customerNames.getOrDefault(
chatList.clear(); dto.getCustomerId(), "Customer #" + dto.getCustomerId());
List<Chat> loaded = response.body().stream() return new Chat(String.valueOf(dto.getId()),
.map(dto -> { name, dto.getLastMessage(),
String name = customerNames.getOrDefault( dto.getCustomerId(), dto.getStaffId());
dto.getCustomerId(), "Customer #" + dto.getCustomerId()); })
return new Chat(String.valueOf(dto.getId()), .collect(Collectors.toList());
name, dto.getLastMessage(), chatList.addAll(loaded);
dto.getCustomerId(), dto.getStaffId()); chatAdapter.notifyDataSetChanged();
})
.collect(Collectors.toList()); if (activeConversationId != null) {
chatList.addAll(loaded); setConversationActive(true);
chatAdapter.notifyDataSetChanged(); // Update title to customer name of active conversation
for (Chat chat : chatList) {
if (activeConversationId != null) { if (chat.getChatId().equals(String.valueOf(activeConversationId))) {
setConversationActive(true); tvChatTitle.setText(chat.getCustomerName());
// Update title to customer name of active conversation break;
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);
} }
} }
if (stompChatManager != null) {
stompChatManager.subscribeToConversation(activeConversationId);
}
loadMessageHistory(activeConversationId);
} else {
messageList.clear();
messageAdapter.notifyDataSetChanged();
setConversationActive(false);
} }
@Override }));
public void onFailure(@NonNull Call<List<ConversationDTO>> 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. * Fetches the full message history for a specific conversation from the API.
*/ */
private void loadMessageHistory(Long conversationId) { private void loadMessageHistory(Long conversationId) {
messageApi.getMessages(conversationId).enqueue(new Callback<List<MessageDTO>>() { messageApi.getMessages(conversationId).enqueue(RetrofitUtils.createSilentCallback(TAG, result -> {
@Override messageList.clear();
public void onResponse(@NonNull Call<List<MessageDTO>> call, for (MessageDTO dto : result) {
@NonNull Response<List<MessageDTO>> response) { messageList.add(dtoToModel(dto));
if (response.isSuccessful() && response.body() != null) {
messageList.clear();
for (MessageDTO dto : response.body()) {
messageList.add(dtoToModel(dto));
}
messageAdapter.notifyDataSetChanged();
scrollToBottom();
}
} }
@Override messageAdapter.notifyDataSetChanged();
public void onFailure(@NonNull Call<List<MessageDTO>> call, scrollToBottom();
@NonNull Throwable t) { }));
Log.e(TAG, "Error loading messages", t);
}
});
} }
/** /**
@@ -339,23 +310,12 @@ public class ChatFragment extends Fragment implements ChatAdapter.OnChatClickLis
//calls api to send the message //calls api to send the message
messageApi.sendMessage(activeConversationId, new SendMessageRequest(text)) messageApi.sendMessage(activeConversationId, new SendMessageRequest(text))
.enqueue(new Callback<MessageDTO>() { .enqueue(RetrofitUtils.createSilentCallback(TAG, result -> {
@Override messageList.add(dtoToModel(result));
public void onResponse(@NonNull Call<MessageDTO> call, messageAdapter.notifyItemInserted(messageList.size() - 1);
@NonNull Response<MessageDTO> response) { scrollToBottom();
if (response.isSuccessful() && response.body() != null) { loadConversations();
messageList.add(dtoToModel(response.body())); }));
messageAdapter.notifyItemInserted(messageList.size() - 1);
scrollToBottom();
loadConversations();
}
}
@Override
public void onFailure(@NonNull Call<MessageDTO> call,
@NonNull Throwable t) {
Log.e(TAG, "Send failed", t);
}
});
} }
/** /**

View File

@@ -27,6 +27,7 @@ import com.example.petstoremobile.utils.FileUtils;
import com.example.petstoremobile.utils.GlideUtils; import com.example.petstoremobile.utils.GlideUtils;
import com.example.petstoremobile.utils.ImagePickerHelper; import com.example.petstoremobile.utils.ImagePickerHelper;
import com.example.petstoremobile.utils.InputValidator; import com.example.petstoremobile.utils.InputValidator;
import com.example.petstoremobile.utils.RetrofitUtils;
import com.example.petstoremobile.utils.UIUtils; import com.example.petstoremobile.utils.UIUtils;
import java.io.File; 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. * Fetches current user profile data from the API and then updates the UI.
*/ */
private void loadProfileData() { private void loadProfileData() {
authApi.getMe().enqueue(new Callback<UserDTO>() { authApi.getMe().enqueue(RetrofitUtils.createCallback(requireContext(), "PROFILE", null, result -> {
@Override currentUser = result;
public void onResponse(Call<UserDTO> call, Response<UserDTO> 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();
//set the user data to the view //set the user data to the view
tvProfileName.setText(currentUser.getFullName()); tvProfileName.setText(currentUser.getFullName());
tvProfileEmail.setText(currentUser.getEmail()); tvProfileEmail.setText(currentUser.getEmail());
tvProfilePhone.setText(currentUser.getPhone()); tvProfilePhone.setText(currentUser.getPhone());
tvProfileRole.setText(currentUser.getRole()); tvProfileRole.setText(currentUser.getRole());
// get the avatar endpoint to load profile image and the token for authorization // get the avatar endpoint to load profile image and the token for authorization
String avatarUrl = baseUrl + AuthApi.AVATAR_FILE_PATH; String avatarUrl = baseUrl + AuthApi.AVATAR_FILE_PATH;
String token = tokenManager.getToken(); String token = tokenManager.getToken();
GlideUtils.loadImageWithToken(requireContext(), imgProfile, avatarUrl, token, R.drawable.placeholder, new GlideUtils.ImageLoadListener() { GlideUtils.loadImageWithToken(requireContext(), imgProfile, avatarUrl, token, R.drawable.placeholder, new GlideUtils.ImageLoadListener() {
@Override @Override
public void onResourceReady() { public void onResourceReady() {
hasImage = true; hasImage = true;
}
@Override
public void onLoadFailed() {
hasImage = false;
}
});
} }
else {
Log.e("onResponse: ", response.message());
ErrorUtils.showErrorMessage(getContext(), response, "Failed to load profile");
}
}
@Override @Override
public void onFailure(Call<UserDTO> call, Throwable t) { public void onLoadFailed() {
Log.e("PROFILE", "onFailure: " + t.getMessage()); hasImage = false;
Toast.makeText(getContext(), "Network error: could not load profile", Toast.LENGTH_SHORT).show(); }
} });
}); }));
} }
/** /**
@@ -245,25 +230,11 @@ public class ProfileFragment extends Fragment {
MultipartBody.Part body = MultipartBody.Part.createFormData("avatar", file.getName(), requestFile); MultipartBody.Part body = MultipartBody.Part.createFormData("avatar", file.getName(), requestFile);
//Call the backend to upload the avatar //Call the backend to upload the avatar
authApi.uploadAvatar(body).enqueue(new Callback<UserDTO>() { authApi.uploadAvatar(body).enqueue(RetrofitUtils.createCallback(requireContext(), "UPLOAD_AVATAR", "Avatar updated successfully", result -> {
@Override currentUser = result;
public void onResponse(Call<UserDTO> call, Response<UserDTO> response) { // Reload image after successful upload
if (response.isSuccessful() && response.body() != null) { loadProfileData();
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<UserDTO> call, Throwable t) {
Log.e("UPLOAD_AVATAR", "Failure: " + t.getMessage());
Toast.makeText(requireContext(), "Network error", Toast.LENGTH_SHORT).show();
}
});
} catch (Exception e) { } catch (Exception e) {
Log.e("UPLOAD_AVATAR", "Error: " + e.getMessage()); 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. * Sends a request to the API to delete the current user's avatar image.
*/ */
private void deleteAvatar() { private void deleteAvatar() {
authApi.deleteAvatar().enqueue(new Callback<Void>() { authApi.deleteAvatar().enqueue(RetrofitUtils.createCallback(requireContext(), "DELETE_AVATAR", "Avatar removed successfully", result -> {
@Override hasImage = false;
public void onResponse(Call<Void> call, Response<Void> response) { imgProfile.setImageResource(R.drawable.placeholder);
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<Void> call, Throwable t) {
Log.e("DELETE_AVATAR", "Failure: " + t.getMessage());
Toast.makeText(requireContext(), "Network error", Toast.LENGTH_SHORT).show();
}
});
} }
/** /**
@@ -300,25 +257,11 @@ public class ProfileFragment extends Fragment {
Map<String, String> updates = new HashMap<>(); Map<String, String> updates = new HashMap<>();
updates.put(fieldName, value); updates.put(fieldName, value);
authApi.updateMe(updates).enqueue(new Callback<UserDTO>() { authApi.updateMe(updates).enqueue(RetrofitUtils.createCallback(requireContext(), "UPDATE_PROFILE", "Profile updated successfully", result -> {
@Override currentUser = result;
public void onResponse(Call<UserDTO> call, Response<UserDTO> response) { // Update the view with the new data from backend
if (response.isSuccessful() && response.body() != null) { tvProfileEmail.setText(currentUser.getEmail());
currentUser = response.body(); tvProfilePhone.setText(currentUser.getPhone());
// 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<UserDTO> call, Throwable t) {
Log.e("UPDATE_PROFILE", "Failure: " + t.getMessage());
Toast.makeText(requireContext(), "Network error", Toast.LENGTH_SHORT).show();
}
});
} }
} }

View File

@@ -7,21 +7,21 @@ import android.view.*;
import android.widget.*; import android.widget.*;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import androidx.navigation.fragment.NavHostFragment; import androidx.navigation.fragment.NavHostFragment;
import com.example.petstoremobile.R; import com.example.petstoremobile.R;
import com.example.petstoremobile.api.*;
import com.example.petstoremobile.dtos.*; import com.example.petstoremobile.dtos.*;
import com.example.petstoremobile.utils.DialogUtils; 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.utils.SpinnerUtils;
import com.example.petstoremobile.viewmodels.AdoptionViewModel;
import com.example.petstoremobile.viewmodels.CustomerViewModel;
import com.example.petstoremobile.viewmodels.PetViewModel;
import java.util.*; import java.util.*;
import javax.inject.Inject;
import dagger.hilt.android.AndroidEntryPoint; import dagger.hilt.android.AndroidEntryPoint;
import retrofit2.*;
/** /**
* Fragment for displaying and editing adoption request details. * Fragment for displaying and editing adoption request details.
@@ -44,9 +44,17 @@ public class AdoptionDetailFragment extends Fragment {
private final String[] STATUSES = {"Pending", "Approved", "Rejected"}; private final String[] STATUSES = {"Pending", "Approved", "Rejected"};
@Inject AdoptionApi adoptionApi; private AdoptionViewModel adoptionViewModel;
@Inject PetApi petApi; private PetViewModel petViewModel;
@Inject CustomerApi customerApi; 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 @Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, 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. * Loads the list of pets from the API.
*/ */
private void loadPets() { private void loadPets() {
petApi.getAllPets(0, 200) petViewModel.getAllPets(0, 200).observe(getViewLifecycleOwner(), resource -> {
.enqueue(new Callback<PageResponse<PetDTO>>() { if (resource.status == Resource.Status.SUCCESS && resource.data != null) {
public void onResponse(Call<PageResponse<PetDTO>> c, petList = resource.data.getContent();
Response<PageResponse<PetDTO>> r) { SpinnerUtils.populateSpinner(requireContext(), spinnerPet, petList,
if (r.isSuccessful() && r.body() != null) { PetDTO::getPetName, "-- Select Pet --",
petList = r.body().getContent(); preselectedPetId, PetDTO::getPetId);
SpinnerUtils.populateSpinner(requireContext(), spinnerPet, petList, }
PetDTO::getPetName, "-- Select Pet --", });
preselectedPetId, PetDTO::getPetId);
}
}
public void onFailure(Call<PageResponse<PetDTO>> c, Throwable t) {
Log.e("ADOPTION", "Pet load failed: " + t.getMessage());
}
});
} }
/** /**
* Loads the list of customers from the API. * Loads the list of customers from the API.
*/ */
private void loadCustomers() { private void loadCustomers() {
customerApi.getAllCustomers(0, 200) customerViewModel.getAllCustomers(0, 200).observe(getViewLifecycleOwner(), resource -> {
.enqueue(new Callback<PageResponse<CustomerDTO>>() { if (resource.status == Resource.Status.SUCCESS && resource.data != null) {
public void onResponse(Call<PageResponse<CustomerDTO>> c, customerList = resource.data.getContent();
Response<PageResponse<CustomerDTO>> r) { SpinnerUtils.populateSpinner(requireContext(), spinnerCustomer, customerList,
if (r.isSuccessful() && r.body() != null) { item -> item.getFirstName() + " " + item.getLastName(),
customerList = r.body().getContent(); "-- Select Customer --",
SpinnerUtils.populateSpinner(requireContext(), spinnerCustomer, customerList, preselectedCustomerId, CustomerDTO::getCustomerId);
item -> item.getFirstName() + " " + item.getLastName(), }
"-- Select Customer --", });
preselectedCustomerId, CustomerDTO::getCustomerId);
}
}
public void onFailure(Call<PageResponse<CustomerDTO>> c, Throwable t) {
Log.e("ADOPTION", "Customer load failed: " + t.getMessage());
}
});
} }
/** /**
@@ -204,51 +198,40 @@ public class AdoptionDetailFragment extends Fragment {
status status
); );
Log.d("ADOPTION_SAVE", "petId=" + pet.getPetId()
+ " customerId=" + customer.getCustomerId()
+ " date=" + date + " status=" + status);
if (isEditing) { if (isEditing) {
adoptionApi.updateAdoption(adoptionId, dto).enqueue(simpleCallback("Updated")); adoptionViewModel.updateAdoption(adoptionId, dto).observe(getViewLifecycleOwner(), resource -> {
} else { if (resource.status == Resource.Status.SUCCESS) {
adoptionApi.createAdoption(dto).enqueue(simpleCallback("Saved")); Toast.makeText(getContext(), "Updated", Toast.LENGTH_SHORT).show();
}
}
/**
* callback for adoption save/update operations.
*/
private Callback<AdoptionDTO> simpleCallback(String msg) {
return new Callback<>() {
public void onResponse(Call<AdoptionDTO> c, Response<AdoptionDTO> r) {
Log.d("ADOPTION_SAVE", "Response: " + r.code());
if (r.isSuccessful()) {
Toast.makeText(getContext(), msg, Toast.LENGTH_SHORT).show();
navigateBack(); navigateBack();
} else { } else if (resource.status == Resource.Status.ERROR) {
ErrorUtils.showErrorMessage(getContext(), r, "Error " + r.code()); Toast.makeText(getContext(), "Error: " + resource.message, Toast.LENGTH_SHORT).show();
} }
} });
public void onFailure(Call<AdoptionDTO> c, Throwable t) { } else {
Log.e("ADOPTION_SAVE", "Failure: " + t.getMessage()); adoptionViewModel.createAdoption(dto).observe(getViewLifecycleOwner(), resource -> {
Toast.makeText(getContext(), "Network error", Toast.LENGTH_SHORT).show(); 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. * Shows a confirmation dialog before deleting an adoption request.
*/ */
private void confirmDelete() { private void confirmDelete() {
DialogUtils.showDeleteConfirmDialog(requireContext(), "Adoption", () -> DialogUtils.showDeleteConfirmDialog(requireContext(), "Adoption", () ->
adoptionApi.deleteAdoption(adoptionId) adoptionViewModel.deleteAdoption(adoptionId).observe(getViewLifecycleOwner(), resource -> {
.enqueue(new Callback<Void>() { if (resource.status == Resource.Status.SUCCESS) {
public void onResponse(Call<Void> c, Response<Void> r) { navigateBack(); } Toast.makeText(getContext(), "Deleted", Toast.LENGTH_SHORT).show();
public void onFailure(Call<Void> c, Throwable t) { navigateBack();
Toast.makeText(getContext(), "Delete failed", } else if (resource.status == Resource.Status.ERROR) {
Toast.LENGTH_SHORT).show(); Toast.makeText(getContext(), "Delete failed: " + resource.message, Toast.LENGTH_SHORT).show();
} }
})); }));
} }
/** /**

View File

@@ -7,21 +7,23 @@ import android.view.*;
import android.widget.*; import android.widget.*;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import androidx.navigation.fragment.NavHostFragment; import androidx.navigation.fragment.NavHostFragment;
import com.example.petstoremobile.R; import com.example.petstoremobile.R;
import com.example.petstoremobile.api.*;
import com.example.petstoremobile.dtos.*; import com.example.petstoremobile.dtos.*;
import com.example.petstoremobile.utils.DialogUtils; 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.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 java.util.*;
import javax.inject.Inject;
import dagger.hilt.android.AndroidEntryPoint; import dagger.hilt.android.AndroidEntryPoint;
import retrofit2.*;
/** /**
* Fragment for displaying and editing appointment details. * Fragment for displaying and editing appointment details.
@@ -46,17 +48,26 @@ public class AppointmentDetailFragment extends Fragment {
private List<ServiceDTO> serviceList = new ArrayList<>(); private List<ServiceDTO> serviceList = new ArrayList<>();
private List<CustomerDTO> customerList = new ArrayList<>(); private List<CustomerDTO> customerList = new ArrayList<>();
private List<StoreDTO> storeList = new ArrayList<>(); private List<StoreDTO> storeList = new ArrayList<>();
private List<AppointmentDTO> allAppointments = new ArrayList<>();
private final Integer[] HOURS = {9,10,11,12,13,14,15,16,17}; private final Integer[] HOURS = {9,10,11,12,13,14,15,16,17};
private final Integer[] MINUTES = {0,15,30,45}; private final Integer[] MINUTES = {0,15,30,45};
private final String[] STATUSES = {"Booked","Completed","Cancelled"}; private final String[] STATUSES = {"Booked","Completed","Cancelled"};
@Inject AppointmentApi appointmentApi; private AppointmentViewModel appointmentViewModel;
@Inject PetApi petApi; private PetViewModel petViewModel;
@Inject ServiceApi serviceApi; private ServiceViewModel serviceViewModel;
@Inject CustomerApi customerApi; private StoreViewModel storeViewModel;
@Inject StoreApi storeApi; 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 @Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
@@ -129,102 +140,63 @@ public class AppointmentDetailFragment extends Fragment {
loadServices(); loadServices();
loadCustomers(); loadCustomers();
loadStores(); loadStores();
loadAllAppointments();
} }
/** /**
* Loads the list of pets from the API. * Loads the list of pets from the ViewModel.
*/ */
private void loadPets() { private void loadPets() {
petApi.getAllPets(0, 200) petViewModel.getAllPets(0, 200).observe(getViewLifecycleOwner(), resource -> {
.enqueue(new Callback<PageResponse<PetDTO>>() { if (resource.status == Resource.Status.SUCCESS && resource.data != null) {
public void onResponse(Call<PageResponse<PetDTO>> c, Response<PageResponse<PetDTO>> r) { petList = resource.data.getContent();
if (r.isSuccessful() && r.body() != null) { SpinnerUtils.populateSpinner(requireContext(), spinnerPet, petList,
petList = r.body().getContent(); PetDTO::getPetName, "-- Select Pet --",
SpinnerUtils.populateSpinner(requireContext(), spinnerPet, petList, preselectedPetId, PetDTO::getPetId);
PetDTO::getPetName, "-- Select Pet --", }
preselectedPetId, PetDTO::getPetId); });
}
}
public void onFailure(Call<PageResponse<PetDTO>> c, Throwable t) {
Log.e("APPT", "Pet load failed: " + t.getMessage());
}
});
} }
/** /**
* Loads the list of services from the API. * Loads the list of services from the API.
*/ */
private void loadServices() { private void loadServices() {
serviceApi.getAllServices(0, 200) serviceViewModel.getAllServices(0, 200).observe(getViewLifecycleOwner(), resource -> {
.enqueue(new Callback<PageResponse<ServiceDTO>>() { if (resource.status == Resource.Status.SUCCESS && resource.data != null) {
public void onResponse(Call<PageResponse<ServiceDTO>> c, Response<PageResponse<ServiceDTO>> r) { serviceList = resource.data.getContent();
if (r.isSuccessful() && r.body() != null) { SpinnerUtils.populateSpinner(requireContext(), spinnerService, serviceList,
serviceList = r.body().getContent(); ServiceDTO::getServiceName, "-- Select Service --",
SpinnerUtils.populateSpinner(requireContext(), spinnerService, serviceList, preselectedServiceId, ServiceDTO::getServiceId);
ServiceDTO::getServiceName, "-- Select Service --", }
preselectedServiceId, ServiceDTO::getServiceId); });
}
}
public void onFailure(Call<PageResponse<ServiceDTO>> c, Throwable t) {
Log.e("APPT", "Service load failed: " + t.getMessage());
}
});
} }
/** /**
* Loads the list of customers from the API. * Loads the list of customers from the API.
*/ */
private void loadCustomers() { private void loadCustomers() {
customerApi.getAllCustomers(0, 200) customerViewModel.getAllCustomers(0, 200).observe(getViewLifecycleOwner(), resource -> {
.enqueue(new Callback<PageResponse<CustomerDTO>>() { if (resource.status == Resource.Status.SUCCESS && resource.data != null) {
public void onResponse(Call<PageResponse<CustomerDTO>> c, Response<PageResponse<CustomerDTO>> r) { customerList = resource.data.getContent();
if (r.isSuccessful() && r.body() != null) { SpinnerUtils.populateSpinner(requireContext(), spinnerCustomer, customerList,
customerList = r.body().getContent(); item -> item.getFirstName() + " " + item.getLastName(),
SpinnerUtils.populateSpinner(requireContext(), spinnerCustomer, customerList, "-- Select Customer --",
item -> item.getFirstName() + " " + item.getLastName(), preselectedCustomerId, CustomerDTO::getCustomerId);
"-- Select Customer --", }
preselectedCustomerId, CustomerDTO::getCustomerId); });
}
}
public void onFailure(Call<PageResponse<CustomerDTO>> c, Throwable t) {
Log.e("APPT", "Customer load failed: " + t.getMessage());
}
});
} }
/** /**
* Loads the list of stores from the API. * Loads the list of stores from the API.
*/ */
private void loadStores() { private void loadStores() {
storeApi.getAllStores(0, 50) storeViewModel.getAllStores(0, 50).observe(getViewLifecycleOwner(), resource -> {
.enqueue(new Callback<PageResponse<StoreDTO>>() { if (resource.status == Resource.Status.SUCCESS && resource.data != null) {
public void onResponse(Call<PageResponse<StoreDTO>> c, Response<PageResponse<StoreDTO>> r) { storeList = resource.data.getContent();
if (r.isSuccessful() && r.body() != null) { SpinnerUtils.populateSpinner(requireContext(), spinnerStore, storeList,
storeList = r.body().getContent(); StoreDTO::getStoreName, "-- Select Store --",
SpinnerUtils.populateSpinner(requireContext(), spinnerStore, storeList, preselectedStoreId, StoreDTO::getStoreId);
StoreDTO::getStoreName, "-- Select Store --", }
preselectedStoreId, StoreDTO::getStoreId); });
}
}
public void onFailure(Call<PageResponse<StoreDTO>> 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<PageResponse<AppointmentDTO>>() {
public void onResponse(Call<PageResponse<AppointmentDTO>> c, Response<PageResponse<AppointmentDTO>> r) {
if (r.isSuccessful() && r.body() != null)
allAppointments = r.body().getContent();
}
public void onFailure(Call<PageResponse<AppointmentDTO>> c, Throwable t) {}
});
} }
/** /**
@@ -337,57 +309,36 @@ public class AppointmentDetailFragment extends Fragment {
Collections.singletonList(pet.getPetId()) Collections.singletonList(pet.getPetId())
); );
Log.d("APPT_SAVE", "customerId=" + customer.getCustomerId() androidx.lifecycle.Observer<Resource<AppointmentDTO>> observer = resource -> {
+ " storeId=" + store.getStoreId() if (resource.status == Resource.Status.SUCCESS) {
+ " serviceId=" + service.getServiceId() Toast.makeText(getContext(), isEditing ? "Updated" : "Saved", Toast.LENGTH_SHORT).show();
+ " petId=" + pet.getPetId() navigateBack();
+ " date=" + date + " time=" + time); } else if (resource.status == Resource.Status.ERROR) {
handleSaveError(resource.message);
}
};
if (isEditing) { if (isEditing) {
appointmentApi.updateAppointment(appointmentId, dto).enqueue(simpleCallback("Updated")); appointmentViewModel.updateAppointment(appointmentId, dto).observe(getViewLifecycleOwner(), observer);
} else { } else {
appointmentApi.createAppointment(dto).enqueue(simpleCallback("Saved")); appointmentViewModel.createAppointment(dto).observe(getViewLifecycleOwner(), observer);
} }
} }
/** private void handleSaveError(String errorMessage) {
* callback for appointment save/update operations. if (errorMessage != null) {
*/ Log.e("APPT_SAVE", "Error: " + errorMessage);
private Callback<AppointmentDTO> simpleCallback(String msg) { if (errorMessage.toLowerCase().contains("future")) {
return new Callback<>() { DialogUtils.showInfoDialog(requireContext(), "Invalid Date/Time",
public void onResponse(Call<AppointmentDTO> c, Response<AppointmentDTO> r) { "Booked appointments must be scheduled in the future.");
Log.d("APPT_SAVE", "Response: " + r.code()); } else if (errorMessage.toLowerCase().contains("not available")) {
if (r.isSuccessful()) { showNoAvailabilityDialog();
Toast.makeText(getContext(), msg, Toast.LENGTH_SHORT).show(); } else {
navigateBack(); Toast.makeText(getContext(), "Operation failed", Toast.LENGTH_SHORT).show();
} 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.");
}
}
} }
} else {
public void onFailure(Call<AppointmentDTO> c, Throwable t) { Toast.makeText(getContext(), "Something went wrong", Toast.LENGTH_SHORT).show();
Log.e("APPT_SAVE", "Failure: " + t.getMessage()); }
Toast.makeText(getContext(), "Network error", Toast.LENGTH_SHORT).show();
}
};
} }
/** /**
@@ -396,7 +347,7 @@ public class AppointmentDetailFragment extends Fragment {
private void showNoAvailabilityDialog() { private void showNoAvailabilityDialog() {
new androidx.appcompat.app.AlertDialog.Builder(requireContext()) new androidx.appcompat.app.AlertDialog.Builder(requireContext())
.setTitle("No Availability") .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()) .setPositiveButton("Change Time", (d, w) -> d.dismiss())
.setNegativeButton("Cancel Booking", (d, w) -> navigateBack()) .setNegativeButton("Cancel Booking", (d, w) -> navigateBack())
.setCancelable(false) .setCancelable(false)
@@ -407,14 +358,15 @@ public class AppointmentDetailFragment extends Fragment {
* Shows a confirmation dialog and handles the deletion of an appointment. * Shows a confirmation dialog and handles the deletion of an appointment.
*/ */
private void confirmDelete() { private void confirmDelete() {
DialogUtils.showDeleteConfirmDialog(requireContext(), "Appointment", () -> DialogUtils.showDeleteConfirmDialog(requireContext(), "Appointment", () ->
appointmentApi.deleteAppointment(appointmentId) appointmentViewModel.deleteAppointment(appointmentId).observe(getViewLifecycleOwner(), resource -> {
.enqueue(new Callback<Void>() { if (resource.status == Resource.Status.SUCCESS) {
public void onResponse(Call<Void> c, Response<Void> r) { navigateBack(); } Toast.makeText(getContext(), "Deleted", Toast.LENGTH_SHORT).show();
public void onFailure(Call<Void> c, Throwable t) { navigateBack();
Toast.makeText(getContext(), "Delete failed", Toast.LENGTH_SHORT).show(); } else if (resource.status == Resource.Status.ERROR) {
} Toast.makeText(getContext(), "Delete failed", Toast.LENGTH_SHORT).show();
})); }
}));
} }
/** /**

View File

@@ -14,30 +14,26 @@ import android.widget.Button;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import androidx.navigation.fragment.NavHostFragment; import androidx.navigation.fragment.NavHostFragment;
import com.example.petstoremobile.R; import com.example.petstoremobile.R;
import com.example.petstoremobile.adapters.BlackTextArrayAdapter; 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.InventoryDTO;
import com.example.petstoremobile.dtos.InventoryRequest; import com.example.petstoremobile.dtos.InventoryRequest;
import com.example.petstoremobile.dtos.PageResponse;
import com.example.petstoremobile.dtos.ProductDTO; import com.example.petstoremobile.dtos.ProductDTO;
import com.example.petstoremobile.utils.ErrorUtils;
import com.example.petstoremobile.utils.InputValidator; 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.ArrayList;
import java.util.List; import java.util.List;
import javax.inject.Inject;
import dagger.hilt.android.AndroidEntryPoint; import dagger.hilt.android.AndroidEntryPoint;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
/** /**
* Fragment for displaying and editing inventory item details. * Fragment for displaying and editing inventory item details.
@@ -50,8 +46,8 @@ public class InventoryDetailFragment extends Fragment {
private android.widget.EditText etQuantity; private android.widget.EditText etQuantity;
private Button btnSave, btnDelete, btnBack; private Button btnSave, btnDelete, btnBack;
@Inject InventoryApi inventoryApi; private InventoryViewModel inventoryViewModel;
@Inject ProductApi productApi; private ProductViewModel productViewModel;
private boolean isEditing = false; private boolean isEditing = false;
private long inventoryId = -1; private long inventoryId = -1;
@@ -68,7 +64,14 @@ public class InventoryDetailFragment extends Fragment {
private ArrayAdapter<String> dropdownAdapter; private ArrayAdapter<String> dropdownAdapter;
@Override @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) { Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_inventory_detail, container, false); 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. * Searches for products matching the query from the backend.
*/ */
private void searchProducts(String query) { private void searchProducts(String query) {
productApi.getAllProducts(query, 0, 20).enqueue(new Callback<PageResponse<ProductDTO>>() { productViewModel.getAllProducts(query, 0, 20).observe(getViewLifecycleOwner(), resource -> {
@Override if (resource.status == Resource.Status.SUCCESS && resource.data != null) {
public void onResponse(Call<PageResponse<ProductDTO>> call, productSuggestions.clear();
Response<PageResponse<ProductDTO>> response) { productSuggestions.addAll(resource.data.getContent());
if (response.isSuccessful() && response.body() != null) {
productSuggestions.clear();
productSuggestions.addAll(response.body().getContent());
// Build display strings: "Product Name (ID: X)" // Build display strings: "Product Name (ID: X)"
List<String> names = new ArrayList<>(); List<String> names = new ArrayList<>();
for (ProductDTO p : productSuggestions) { for (ProductDTO p : productSuggestions) {
names.add(p.getProdName() + " (ID: " + p.getProdId() + ")"); names.add(p.getProdName() + " (ID: " + p.getProdId() + ")");
}
dropdownAdapter.clear();
dropdownAdapter.addAll(names);
dropdownAdapter.notifyDataSetChanged();
etProductSearch.showDropDown();
} }
}
@Override dropdownAdapter.clear();
public void onFailure(Call<PageResponse<ProductDTO>> call, Throwable t) { dropdownAdapter.addAll(names);
Toast.makeText(getContext(), "Failed to load products", Toast.LENGTH_SHORT).show(); dropdownAdapter.notifyDataSetChanged();
etProductSearch.showDropDown();
} }
}); });
} }
@@ -242,41 +236,23 @@ public class InventoryDetailFragment extends Fragment {
setButtonsEnabled(false); setButtonsEnabled(false);
if (isEditing) { if (isEditing) {
inventoryApi.updateInventory(inventoryId, request).enqueue(new Callback<InventoryDTO>() { inventoryViewModel.updateInventory(inventoryId, request).observe(getViewLifecycleOwner(), resource -> {
@Override setButtonsEnabled(true);
public void onResponse(Call<InventoryDTO> call, Response<InventoryDTO> response) { if (resource.status == Resource.Status.SUCCESS) {
setButtonsEnabled(true); Toast.makeText(getContext(), "Inventory updated", Toast.LENGTH_SHORT).show();
if (response.isSuccessful()) { navigateBack();
Toast.makeText(getContext(), "Inventory updated", Toast.LENGTH_SHORT).show(); } else if (resource.status == Resource.Status.ERROR) {
navigateBack(); Toast.makeText(getContext(), "Error: " + resource.message, Toast.LENGTH_SHORT).show();
} else {
ErrorUtils.showErrorMessage(getContext(), response, "Update failed");
}
}
@Override
public void onFailure(Call<InventoryDTO> call, Throwable t) {
setButtonsEnabled(true);
Toast.makeText(getContext(), "Network error", Toast.LENGTH_SHORT).show();
} }
}); });
} else { } else {
inventoryApi.createInventory(request).enqueue(new Callback<InventoryDTO>() { inventoryViewModel.createInventory(request).observe(getViewLifecycleOwner(), resource -> {
@Override setButtonsEnabled(true);
public void onResponse(Call<InventoryDTO> call, Response<InventoryDTO> response) { if (resource.status == Resource.Status.SUCCESS) {
setButtonsEnabled(true); Toast.makeText(getContext(), "Inventory created", Toast.LENGTH_SHORT).show();
if (response.isSuccessful()) { navigateBack();
Toast.makeText(getContext(), "Inventory created", Toast.LENGTH_SHORT).show(); } else if (resource.status == Resource.Status.ERROR) {
navigateBack(); Toast.makeText(getContext(), "Error: " + resource.message, Toast.LENGTH_SHORT).show();
} else {
ErrorUtils.showErrorMessage(getContext(), response, "Create failed");
}
}
@Override
public void onFailure(Call<InventoryDTO> call, Throwable t) {
setButtonsEnabled(true);
Toast.makeText(getContext(), "Network error", Toast.LENGTH_SHORT).show();
} }
}); });
} }
@@ -299,22 +275,13 @@ public class InventoryDetailFragment extends Fragment {
*/ */
private void deleteInventory() { private void deleteInventory() {
setButtonsEnabled(false); setButtonsEnabled(false);
inventoryApi.deleteInventory(inventoryId).enqueue(new Callback<Void>() { inventoryViewModel.deleteInventory(inventoryId).observe(getViewLifecycleOwner(), resource -> {
@Override setButtonsEnabled(true);
public void onResponse(Call<Void> call, Response<Void> response) { if (resource.status == Resource.Status.SUCCESS) {
setButtonsEnabled(true); Toast.makeText(getContext(), "Inventory deleted", Toast.LENGTH_SHORT).show();
if (response.isSuccessful()) { navigateBack();
Toast.makeText(getContext(), "Inventory deleted", Toast.LENGTH_SHORT).show(); } else if (resource.status == Resource.Status.ERROR) {
navigateBack(); Toast.makeText(getContext(), "Delete failed: " + resource.message, Toast.LENGTH_SHORT).show();
} else {
ErrorUtils.showErrorMessage(getContext(), response, "Delete failed");
}
}
@Override
public void onFailure(Call<Void> call, Throwable t) {
setButtonsEnabled(true);
Toast.makeText(getContext(), "Network error", Toast.LENGTH_SHORT).show();
} }
}); });
} }

View File

@@ -4,9 +4,9 @@ import android.os.Bundle;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import androidx.navigation.fragment.NavHostFragment; import androidx.navigation.fragment.NavHostFragment;
import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
@@ -17,20 +17,15 @@ import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import com.example.petstoremobile.R; import com.example.petstoremobile.R;
import com.example.petstoremobile.api.PetApi;
import com.example.petstoremobile.dtos.PetDTO; import com.example.petstoremobile.dtos.PetDTO;
import com.example.petstoremobile.utils.ActivityLogger; import com.example.petstoremobile.utils.ActivityLogger;
import com.example.petstoremobile.utils.DialogUtils; import com.example.petstoremobile.utils.DialogUtils;
import com.example.petstoremobile.utils.ErrorUtils;
import com.example.petstoremobile.utils.InputValidator; import com.example.petstoremobile.utils.InputValidator;
import com.example.petstoremobile.utils.Resource;
import com.example.petstoremobile.utils.SpinnerUtils; import com.example.petstoremobile.utils.SpinnerUtils;
import com.example.petstoremobile.viewmodels.PetViewModel;
import javax.inject.Inject;
import dagger.hilt.android.AndroidEntryPoint; import dagger.hilt.android.AndroidEntryPoint;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
/** /**
* Fragment for displaying and editing pet details. * Fragment for displaying and editing pet details.
@@ -45,7 +40,13 @@ public class PetDetailFragment extends Fragment {
private int petId; private int petId;
private boolean isEditing = false; 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 @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, public View onCreateView(LayoutInflater inflater, ViewGroup container,
@@ -97,44 +98,24 @@ public class PetDetailFragment extends Fragment {
if (isEditing) { if (isEditing) {
// Update existing pet // Update existing pet
petDTO.setPetId((long) petId); petDTO.setPetId((long) petId);
petApi.updatePet((long) petId, petDTO).enqueue(new Callback<PetDTO>() { viewModel.updatePet((long) petId, petDTO).observe(getViewLifecycleOwner(), resource -> {
@Override if (resource.status == Resource.Status.SUCCESS) {
public void onResponse(Call<PetDTO> call, Response<PetDTO> response) { ActivityLogger.logChange(requireContext(), "Pet", "UPDATED", petId);
if (response.isSuccessful()) { Toast.makeText(getContext(), "Pet updated successfully!", Toast.LENGTH_SHORT).show();
ActivityLogger.logChange(requireContext(), "Pet", "UPDATED", petId); navigateBack();
Toast.makeText(getContext(), "Pet updated successfully!", Toast.LENGTH_SHORT).show(); } else if (resource.status == Resource.Status.ERROR) {
navigateBack(); Toast.makeText(getContext(), "Error: " + resource.message, Toast.LENGTH_SHORT).show();
} else {
ErrorUtils.showErrorMessage(getContext(), response, "Failed to update pet");
}
}
@Override
public void onFailure(Call<PetDTO> 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();
} }
}); });
} else { } else {
// Add new pet // Add new pet
petApi.createPet(petDTO).enqueue(new Callback<PetDTO>() { viewModel.createPet(petDTO).observe(getViewLifecycleOwner(), resource -> {
@Override if (resource.status == Resource.Status.SUCCESS) {
public void onResponse(Call<PetDTO> call, Response<PetDTO> response) { ActivityLogger.log(requireContext(), "Added new Pet: " + name);
if (response.isSuccessful()) { Toast.makeText(getContext(), "Pet added successfully!", Toast.LENGTH_SHORT).show();
ActivityLogger.log(requireContext(), "Added new Pet: " + name); navigateBack();
Toast.makeText(getContext(), "Pet added successfully!", Toast.LENGTH_SHORT).show(); } else if (resource.status == Resource.Status.ERROR) {
navigateBack(); Toast.makeText(getContext(), "Error: " + resource.message, Toast.LENGTH_SHORT).show();
} else {
ErrorUtils.showErrorMessage(getContext(), response, "Failed to add pet");
}
}
@Override
public void onFailure(Call<PetDTO> 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();
} }
}); });
} }
@@ -145,23 +126,13 @@ public class PetDetailFragment extends Fragment {
*/ */
private void deletePet() { private void deletePet() {
DialogUtils.showDeleteConfirmDialog(requireContext(), "Pet", () -> DialogUtils.showDeleteConfirmDialog(requireContext(), "Pet", () ->
petApi.deletePet((long) petId).enqueue(new Callback<Void>() { viewModel.deletePet((long) petId).observe(getViewLifecycleOwner(), resource -> {
@Override if (resource.status == Resource.Status.SUCCESS) {
public void onResponse(Call<Void> call, Response<Void> response) { ActivityLogger.logChange(requireContext(), "Pet", "DELETED", petId);
if (response.isSuccessful()) { Toast.makeText(getContext(), "Pet deleted successfully!", Toast.LENGTH_SHORT).show();
ActivityLogger.logChange(requireContext(), "Pet", "DELETED", petId); navigateBack();
Toast.makeText(getContext(), "Pet deleted successfully!", Toast.LENGTH_SHORT).show(); } else if (resource.status == Resource.Status.ERROR) {
navigateBack(); Toast.makeText(getContext(), "Delete failed: " + resource.message, Toast.LENGTH_SHORT).show();
} else {
ErrorUtils.showErrorMessage(getContext(), response, "Failed to delete pet");
}
}
@Override
public void onFailure(Call<Void> 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();
} }
})); }));
} }
@@ -189,9 +160,7 @@ public class PetDetailFragment extends Fragment {
etPetBreed.setText(getArguments().getString("petBreed")); etPetBreed.setText(getArguments().getString("petBreed"));
etPetAge.setText(String.valueOf(getArguments().getInt("petAge"))); etPetAge.setText(String.valueOf(getArguments().getInt("petAge")));
etPetPrice.setText(String.valueOf(getArguments().getDouble("petPrice"))); etPetPrice.setText(String.valueOf(getArguments().getDouble("petPrice")));
SpinnerUtils.setSelectionByValue(spinnerPetStatus, getArguments().getString("petStatus")); SpinnerUtils.setSelectionByValue(spinnerPetStatus, getArguments().getString("petStatus"));
btnDeletePet.setVisibility(View.VISIBLE); btnDeletePet.setVisibility(View.VISIBLE);
} else { } else {
// Pet is being added // Pet is being added
@@ -228,5 +197,4 @@ public class PetDetailFragment extends Fragment {
SpinnerUtils.setupStringSpinner(requireContext(), spinnerPetStatus, SpinnerUtils.setupStringSpinner(requireContext(), spinnerPetStatus,
new String[]{"Available", "Adopted"}); new String[]{"Available", "Adopted"});
} }
} }

View File

@@ -1,31 +1,30 @@
package com.example.petstoremobile.fragments.listfragments.detailfragments; package com.example.petstoremobile.fragments.listfragments.detailfragments;
import android.os.Bundle; import android.os.Bundle;
import android.util.Log;
import android.view.*; import android.view.*;
import android.widget.*; import android.widget.*;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import androidx.navigation.fragment.NavHostFragment; import androidx.navigation.fragment.NavHostFragment;
import com.example.petstoremobile.R; import com.example.petstoremobile.R;
import com.example.petstoremobile.api.*;
import com.example.petstoremobile.dtos.*; import com.example.petstoremobile.dtos.*;
import com.example.petstoremobile.utils.DialogUtils; import com.example.petstoremobile.utils.DialogUtils;
import com.example.petstoremobile.utils.ErrorUtils;
import com.example.petstoremobile.utils.InputValidator; import com.example.petstoremobile.utils.InputValidator;
import com.example.petstoremobile.utils.Resource;
import com.example.petstoremobile.utils.SpinnerUtils; 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.math.BigDecimal;
import java.util.*; import java.util.*;
import javax.inject.Inject;
import dagger.hilt.android.AndroidEntryPoint; 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 @AndroidEntryPoint
public class ProductSupplierDetailFragment extends Fragment { public class ProductSupplierDetailFragment extends Fragment {
@@ -44,9 +43,17 @@ public class ProductSupplierDetailFragment extends Fragment {
private List<ProductDTO> productList = new ArrayList<>(); private List<ProductDTO> productList = new ArrayList<>();
private List<SupplierDTO> supplierList = new ArrayList<>(); private List<SupplierDTO> supplierList = new ArrayList<>();
@Inject ProductSupplierApi productSupplierApi; private ProductSupplierViewModel psViewModel;
@Inject ProductApi productApi; private ProductViewModel productViewModel;
@Inject SupplierApi supplierApi; 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 @Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, 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. * Loads the list of products from the API.
*/ */
private void loadProducts() { private void loadProducts() {
productApi.getAllProducts(null, 0, 200) productViewModel.getAllProducts(null, 0, 200).observe(getViewLifecycleOwner(), resource -> {
.enqueue(new Callback<PageResponse<ProductDTO>>() { if (resource.status == Resource.Status.SUCCESS && resource.data != null) {
public void onResponse(Call<PageResponse<ProductDTO>> c, productList = resource.data.getContent();
Response<PageResponse<ProductDTO>> r) { SpinnerUtils.populateSpinner(requireContext(), spinnerProduct, productList,
if (r.isSuccessful() && r.body() != null) { ProductDTO::getProdName, "-- Select Product --",
productList = r.body().getContent(); preselectedProductId, ProductDTO::getProdId);
SpinnerUtils.populateSpinner(requireContext(), spinnerProduct, productList, }
ProductDTO::getProdName, "-- Select Product --", });
preselectedProductId, ProductDTO::getProdId);
}
}
public void onFailure(Call<PageResponse<ProductDTO>> c, Throwable t) {
Log.e("PSDetail", "Product load failed: " + t.getMessage());
}
});
} }
/** /**
* Loads the list of suppliers from the API. * Loads the list of suppliers from the API.
*/ */
private void loadSuppliers() { private void loadSuppliers() {
supplierApi.getAllSuppliers(0, 200) supplierViewModel.getAllSuppliers(0, 200).observe(getViewLifecycleOwner(), resource -> {
.enqueue(new Callback<PageResponse<SupplierDTO>>() { if (resource.status == Resource.Status.SUCCESS && resource.data != null) {
public void onResponse(Call<PageResponse<SupplierDTO>> c, supplierList = resource.data.getContent();
Response<PageResponse<SupplierDTO>> r) { SpinnerUtils.populateSpinner(requireContext(), spinnerSupplier, supplierList,
if (r.isSuccessful() && r.body() != null) { SupplierDTO::getSupCompany, "-- Select Supplier --",
supplierList = r.body().getContent(); preselectedSupplierId, SupplierDTO::getSupId);
SpinnerUtils.populateSpinner(requireContext(), spinnerSupplier, supplierList, }
SupplierDTO::getSupCompany, "-- Select Supplier --", });
preselectedSupplierId, SupplierDTO::getSupId);
}
}
public void onFailure(Call<PageResponse<SupplierDTO>> c, Throwable t) {
Log.e("PSDetail", "Supplier load failed: " + t.getMessage());
}
});
} }
/** /**
@@ -169,48 +162,39 @@ public class ProductSupplierDetailFragment extends Fragment {
product.getProdId(), supplier.getSupId(), cost); product.getProdId(), supplier.getSupId(), cost);
if (isEditing) { if (isEditing) {
productSupplierApi.updateProductSupplier(editProductId, editSupplierId, dto) psViewModel.updateProductSupplier(editProductId, editSupplierId, dto).observe(getViewLifecycleOwner(), resource -> {
.enqueue(simpleCallback("Updated")); if (resource.status == Resource.Status.SUCCESS) {
} else { Toast.makeText(getContext(), "Updated", Toast.LENGTH_SHORT).show();
productSupplierApi.createProductSupplier(dto).enqueue(simpleCallback("Saved"));
}
}
/**
* callback for product-supplier save/update operations.
*/
private Callback<ProductSupplierDTO> simpleCallback(String msg) {
return new Callback<>() {
public void onResponse(Call<ProductSupplierDTO> c, Response<ProductSupplierDTO> r) {
if (r.isSuccessful()) {
Toast.makeText(getContext(), msg, Toast.LENGTH_SHORT).show();
navigateBack(); navigateBack();
} else { } else if (resource.status == Resource.Status.ERROR) {
ErrorUtils.showErrorMessage(getContext(), r, "Error " + r.code()); Toast.makeText(getContext(), "Error: " + resource.message, Toast.LENGTH_SHORT).show();
} }
} });
public void onFailure(Call<ProductSupplierDTO> c, Throwable t) { } else {
Log.e("PS_SAVE", "Failure: " + t.getMessage()); psViewModel.createProductSupplier(dto).observe(getViewLifecycleOwner(), resource -> {
Toast.makeText(getContext(), "Network error", Toast.LENGTH_SHORT).show(); 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. * Shows a confirmation dialog before deleting a product-supplier relationship.
*/ */
private void confirmDelete() { private void confirmDelete() {
DialogUtils.showDeleteConfirmDialog(requireContext(), "Product Supplier", () -> DialogUtils.showDeleteConfirmDialog(requireContext(), "Product Supplier", () ->
productSupplierApi.deleteProductSupplier(editProductId, editSupplierId) psViewModel.deleteProductSupplier(editProductId, editSupplierId).observe(getViewLifecycleOwner(), resource -> {
.enqueue(new Callback<Void>() { if (resource.status == Resource.Status.SUCCESS) {
public void onResponse(Call<Void> c, Response<Void> r) { Toast.makeText(getContext(), "Deleted", Toast.LENGTH_SHORT).show();
navigateBack(); navigateBack();
} } else if (resource.status == Resource.Status.ERROR) {
public void onFailure(Call<Void> c, Throwable t) { Toast.makeText(getContext(), "Delete failed: " + resource.message, Toast.LENGTH_SHORT).show();
Toast.makeText(getContext(), "Delete failed", }
Toast.LENGTH_SHORT).show(); }));
}
}));
} }
/** /**

View File

@@ -2,10 +2,11 @@ package com.example.petstoremobile.fragments.listfragments.detailfragments;
import android.os.Bundle; import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import androidx.navigation.fragment.NavHostFragment; import androidx.navigation.fragment.NavHostFragment;
import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
@@ -15,19 +16,14 @@ import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import com.example.petstoremobile.R; import com.example.petstoremobile.R;
import com.example.petstoremobile.api.ServiceApi;
import com.example.petstoremobile.dtos.ServiceDTO; import com.example.petstoremobile.dtos.ServiceDTO;
import com.example.petstoremobile.utils.ActivityLogger; import com.example.petstoremobile.utils.ActivityLogger;
import com.example.petstoremobile.utils.DialogUtils; import com.example.petstoremobile.utils.DialogUtils;
import com.example.petstoremobile.utils.ErrorUtils;
import com.example.petstoremobile.utils.InputValidator; import com.example.petstoremobile.utils.InputValidator;
import com.example.petstoremobile.utils.Resource;
import javax.inject.Inject; import com.example.petstoremobile.viewmodels.ServiceViewModel;
import dagger.hilt.android.AndroidEntryPoint; import dagger.hilt.android.AndroidEntryPoint;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
/** /**
* Fragment for displaying and editing service details. * Fragment for displaying and editing service details.
@@ -41,10 +37,16 @@ public class ServiceDetailFragment extends Fragment {
private int serviceId; private int serviceId;
private boolean isEditing = false; private boolean isEditing = false;
@Inject ServiceApi serviceApi; private ServiceViewModel viewModel;
@Override @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) { Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_service_detail, container, false); View view = inflater.inflate(R.layout.fragment_service_detail, container, false);
@@ -87,44 +89,23 @@ public class ServiceDetailFragment extends Fragment {
if (isEditing) { if (isEditing) {
// Update existing service // Update existing service
serviceDTO.setServiceId((long) serviceId); serviceDTO.setServiceId((long) serviceId);
serviceApi.updateService((long) serviceId, serviceDTO).enqueue(new Callback<ServiceDTO>() { viewModel.updateService((long) serviceId, serviceDTO).observe(getViewLifecycleOwner(), resource -> {
@Override if (resource.status == Resource.Status.SUCCESS) {
public void onResponse(Call<ServiceDTO> call, Response<ServiceDTO> response) { ActivityLogger.logChange(requireContext(), "Service", "UPDATED", serviceId);
if (response.isSuccessful()) { Toast.makeText(getContext(), "Service updated successfully!", Toast.LENGTH_SHORT).show();
ActivityLogger.logChange(requireContext(), "Service", "UPDATED", serviceId); navigateBack();
Toast.makeText(getContext(), "Service updated successfully!", Toast.LENGTH_SHORT).show(); } else if (resource.status == Resource.Status.ERROR) {
navigateBack(); Toast.makeText(getContext(), "Error: " + resource.message, Toast.LENGTH_SHORT).show();
} else {
ErrorUtils.showErrorMessage(getContext(), response, "Failed to update service");
}
}
@Override
public void onFailure(Call<ServiceDTO> 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();
} }
}); });
} else { } else {
// Add new service viewModel.createService(serviceDTO).observe(getViewLifecycleOwner(), resource -> {
serviceApi.createService(serviceDTO).enqueue(new Callback<ServiceDTO>() { if (resource.status == Resource.Status.SUCCESS) {
@Override ActivityLogger.log(requireContext(), "Added new Service: " + name);
public void onResponse(Call<ServiceDTO> call, Response<ServiceDTO> response) { Toast.makeText(getContext(), "Service added successfully!", Toast.LENGTH_SHORT).show();
if (response.isSuccessful()) { navigateBack();
ActivityLogger.log(requireContext(), "Added new Service: " + name); } else if (resource.status == Resource.Status.ERROR) {
Toast.makeText(getContext(), "Service added successfully!", Toast.LENGTH_SHORT).show(); Toast.makeText(getContext(), "Error: " + resource.message, Toast.LENGTH_SHORT).show();
navigateBack();
} else {
ErrorUtils.showErrorMessage(getContext(), response, "Failed to add service");
}
}
@Override
public void onFailure(Call<ServiceDTO> 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();
} }
}); });
} }
@@ -135,23 +116,13 @@ public class ServiceDetailFragment extends Fragment {
*/ */
private void deleteService() { private void deleteService() {
DialogUtils.showDeleteConfirmDialog(requireContext(), "Service", () -> DialogUtils.showDeleteConfirmDialog(requireContext(), "Service", () ->
serviceApi.deleteService((long) serviceId).enqueue(new Callback<Void>() { viewModel.deleteService((long) serviceId).observe(getViewLifecycleOwner(), resource -> {
@Override if (resource.status == Resource.Status.SUCCESS) {
public void onResponse(Call<Void> call, Response<Void> response) { ActivityLogger.logChange(requireContext(), "Service", "DELETED", serviceId);
if (response.isSuccessful()) { Toast.makeText(getContext(), "Service deleted successfully!", Toast.LENGTH_SHORT).show();
ActivityLogger.logChange(requireContext(), "Service", "DELETED", serviceId); navigateBack();
Toast.makeText(getContext(), "Service deleted successfully!", Toast.LENGTH_SHORT).show(); } else if (resource.status == Resource.Status.ERROR) {
navigateBack(); Toast.makeText(getContext(), "Delete failed: " + resource.message, Toast.LENGTH_SHORT).show();
} else {
ErrorUtils.showErrorMessage(getContext(), response, "Failed to delete service");
}
}
@Override
public void onFailure(Call<Void> 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();
} }
})); }));
} }

View File

@@ -2,10 +2,11 @@ package com.example.petstoremobile.fragments.listfragments.detailfragments;
import android.os.Bundle; import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import androidx.navigation.fragment.NavHostFragment; import androidx.navigation.fragment.NavHostFragment;
import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
@@ -15,20 +16,15 @@ import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import com.example.petstoremobile.R; import com.example.petstoremobile.R;
import com.example.petstoremobile.api.SupplierApi;
import com.example.petstoremobile.dtos.SupplierDTO; import com.example.petstoremobile.dtos.SupplierDTO;
import com.example.petstoremobile.utils.ActivityLogger; import com.example.petstoremobile.utils.ActivityLogger;
import com.example.petstoremobile.utils.DialogUtils; import com.example.petstoremobile.utils.DialogUtils;
import com.example.petstoremobile.utils.ErrorUtils;
import com.example.petstoremobile.utils.InputValidator; import com.example.petstoremobile.utils.InputValidator;
import com.example.petstoremobile.utils.Resource;
import com.example.petstoremobile.utils.UIUtils; import com.example.petstoremobile.utils.UIUtils;
import com.example.petstoremobile.viewmodels.SupplierViewModel;
import javax.inject.Inject;
import dagger.hilt.android.AndroidEntryPoint; import dagger.hilt.android.AndroidEntryPoint;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
/** /**
* Fragment for displaying and editing supplier details. * Fragment for displaying and editing supplier details.
@@ -42,10 +38,16 @@ public class SupplierDetailFragment extends Fragment {
private int supId; private int supId;
private boolean isEditing = false; private boolean isEditing = false;
@Inject SupplierApi supplierApi; private SupplierViewModel viewModel;
@Override @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) { Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_supplier_detail, container, false); View view = inflater.inflate(R.layout.fragment_supplier_detail, container, false);
@@ -91,44 +93,24 @@ public class SupplierDetailFragment extends Fragment {
if (isEditing) { if (isEditing) {
// Update existing supplier // Update existing supplier
supplierDTO.setSupId((long) supId); supplierDTO.setSupId((long) supId);
supplierApi.updateSupplier((long) supId, supplierDTO).enqueue(new Callback<SupplierDTO>() { viewModel.updateSupplier((long) supId, supplierDTO).observe(getViewLifecycleOwner(), resource -> {
@Override if (resource.status == Resource.Status.SUCCESS) {
public void onResponse(Call<SupplierDTO> call, Response<SupplierDTO> response) { ActivityLogger.logChange(requireContext(), "Supplier", "UPDATED", supId);
if (response.isSuccessful()) { Toast.makeText(getContext(), "Supplier updated successfully!", Toast.LENGTH_SHORT).show();
ActivityLogger.logChange(requireContext(), "Supplier", "UPDATED", supId); navigateBack();
Toast.makeText(getContext(), "Supplier updated successfully!", Toast.LENGTH_SHORT).show(); } else if (resource.status == Resource.Status.ERROR) {
navigateBack(); Toast.makeText(getContext(), "Error: " + resource.message, Toast.LENGTH_SHORT).show();
} else {
ErrorUtils.showErrorMessage(getContext(), response, "Failed to update supplier");
}
}
@Override
public void onFailure(Call<SupplierDTO> 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();
} }
}); });
} else { } else {
// Add new supplier // Add new supplier
supplierApi.createSupplier(supplierDTO).enqueue(new Callback<SupplierDTO>() { viewModel.createSupplier(supplierDTO).observe(getViewLifecycleOwner(), resource -> {
@Override if (resource.status == Resource.Status.SUCCESS) {
public void onResponse(Call<SupplierDTO> call, Response<SupplierDTO> response) { ActivityLogger.log(requireContext(), "Added new Supplier: " + company);
if (response.isSuccessful()) { Toast.makeText(getContext(), "Supplier added successfully!", Toast.LENGTH_SHORT).show();
ActivityLogger.log(requireContext(), "Added new Supplier: " + company); navigateBack();
Toast.makeText(getContext(), "Supplier added successfully!", Toast.LENGTH_SHORT).show(); } else if (resource.status == Resource.Status.ERROR) {
navigateBack(); Toast.makeText(getContext(), "Error: " + resource.message, Toast.LENGTH_SHORT).show();
} else {
ErrorUtils.showErrorMessage(getContext(), response, "Failed to add supplier");
}
}
@Override
public void onFailure(Call<SupplierDTO> 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();
} }
}); });
} }
@@ -138,24 +120,14 @@ public class SupplierDetailFragment extends Fragment {
* Displays a confirmation dialog and handles the deletion of a supplier. * Displays a confirmation dialog and handles the deletion of a supplier.
*/ */
private void deleteSupplier() { private void deleteSupplier() {
DialogUtils.showDeleteConfirmDialog(requireContext(), "Supplier", () -> DialogUtils.showDeleteConfirmDialog(requireContext(), "Supplier", () ->
supplierApi.deleteSupplier((long) supId).enqueue(new Callback<Void>() { viewModel.deleteSupplier((long) supId).observe(getViewLifecycleOwner(), resource -> {
@Override if (resource.status == Resource.Status.SUCCESS) {
public void onResponse(Call<Void> call, Response<Void> response) { ActivityLogger.logChange(requireContext(), "Supplier", "DELETED", supId);
if (response.isSuccessful()) { Toast.makeText(getContext(), "Supplier deleted successfully!", Toast.LENGTH_SHORT).show();
ActivityLogger.logChange(requireContext(), "Supplier", "DELETED", supId); navigateBack();
Toast.makeText(getContext(), "Supplier deleted successfully!", Toast.LENGTH_SHORT).show(); } else if (resource.status == Resource.Status.ERROR) {
navigateBack(); Toast.makeText(getContext(), "Delete failed: " + resource.message, Toast.LENGTH_SHORT).show();
} else {
ErrorUtils.showErrorMessage(getContext(), response, "Failed to delete supplier");
}
}
@Override
public void onFailure(Call<Void> 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();
} }
})); }));
} }

View File

@@ -13,7 +13,6 @@ import android.view.ViewGroup;
import android.widget.Button; import android.widget.Button;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast;
import com.example.petstoremobile.R; import com.example.petstoremobile.R;
import com.example.petstoremobile.api.PetApi; 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.FileUtils;
import com.example.petstoremobile.utils.GlideUtils; import com.example.petstoremobile.utils.GlideUtils;
import com.example.petstoremobile.utils.ImagePickerHelper; import com.example.petstoremobile.utils.ImagePickerHelper;
import com.example.petstoremobile.utils.RetrofitUtils;
import java.io.File; import java.io.File;
import java.util.Locale; import java.util.Locale;
@@ -32,9 +32,6 @@ import dagger.hilt.android.AndroidEntryPoint;
import okhttp3.MediaType; import okhttp3.MediaType;
import okhttp3.MultipartBody; import okhttp3.MultipartBody;
import okhttp3.RequestBody; import okhttp3.RequestBody;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
@AndroidEntryPoint @AndroidEntryPoint
public class PetProfileFragment extends Fragment { public class PetProfileFragment extends Fragment {
@@ -157,24 +154,12 @@ public class PetProfileFragment extends Fragment {
MultipartBody.Part body = MultipartBody.Part.createFormData("image", file.getName(), requestFile); MultipartBody.Part body = MultipartBody.Part.createFormData("image", file.getName(), requestFile);
// Call the backend to upload the image // Call the backend to upload the image
petApi.uploadPetImage((long) petId, body).enqueue(new Callback<Void>() { petApi.uploadPetImage((long) petId, body).enqueue(RetrofitUtils.createCallback(
@Override requireContext(),
public void onResponse(Call<Void> call, Response<Void> response) { "UPLOAD_PET_IMAGE",
if (response.isSuccessful()) { "Pet photo updated successfully",
Toast.makeText(requireContext(), "Pet photo updated successfully", Toast.LENGTH_SHORT).show(); result -> loadPetImage(petId)
// 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<Void> call, Throwable t) {
Log.e("UPLOAD_PET_IMAGE", "Failure: " + t.getMessage());
Toast.makeText(requireContext(), "Network error", Toast.LENGTH_SHORT).show();
}
});
} catch (Exception e) { } catch (Exception e) {
Log.e("UPLOAD_PET_IMAGE", "Error: " + e.getMessage()); 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. * Sends a request to the API to remove the current pet photo.
*/ */
private void deletePetImage() { private void deletePetImage() {
petApi.deletePetImage((long) petId).enqueue(new Callback<Void>() { petApi.deletePetImage((long) petId).enqueue(RetrofitUtils.createCallback(
@Override requireContext(),
public void onResponse(Call<Void> call, Response<Void> response) { "DELETE_PET_IMAGE",
if (response.isSuccessful()) { "Pet photo removed",
Toast.makeText(requireContext(), "Pet photo removed", Toast.LENGTH_SHORT).show(); result -> {
hasImage = false; hasImage = false;
imgPet.setImageResource(R.drawable.placeholder); imgPet.setImageResource(R.drawable.placeholder);
} else {
Toast.makeText(requireContext(), "Failed to remove pet photo", Toast.LENGTH_SHORT).show();
} }
} ));
@Override
public void onFailure(Call<Void> call, Throwable t) {
Log.e("DELETE_PET_IMAGE", "Failure: " + t.getMessage());
Toast.makeText(requireContext(), "Network error", Toast.LENGTH_SHORT).show();
}
});
} }
} }

View File

@@ -7,16 +7,14 @@ import com.example.petstoremobile.api.AdoptionApi;
import com.example.petstoremobile.dtos.AdoptionDTO; import com.example.petstoremobile.dtos.AdoptionDTO;
import com.example.petstoremobile.dtos.PageResponse; import com.example.petstoremobile.dtos.PageResponse;
import com.example.petstoremobile.utils.Resource; import com.example.petstoremobile.utils.Resource;
import com.example.petstoremobile.utils.RetrofitUtils;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
@Singleton @Singleton
public class AdoptionRepository { public class AdoptionRepository {
private static final String TAG = "AdoptionRepository";
private final AdoptionApi adoptionApi; private final AdoptionApi adoptionApi;
@Inject @Inject
@@ -31,21 +29,8 @@ public class AdoptionRepository {
MutableLiveData<Resource<PageResponse<AdoptionDTO>>> data = new MutableLiveData<>(); MutableLiveData<Resource<PageResponse<AdoptionDTO>>> data = new MutableLiveData<>();
data.setValue(Resource.loading(null)); data.setValue(Resource.loading(null));
adoptionApi.getAllAdoptions(page, size).enqueue(new Callback<PageResponse<AdoptionDTO>>() { adoptionApi.getAllAdoptions(page, size).enqueue(RetrofitUtils.createSilentCallback(TAG,
@Override result -> data.setValue(Resource.success(result))));
public void onResponse(Call<PageResponse<AdoptionDTO>> call, Response<PageResponse<AdoptionDTO>> 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<PageResponse<AdoptionDTO>> call, Throwable t) {
data.setValue(Resource.error(t.getMessage(), null));
}
});
return data; return data;
} }
@@ -57,21 +42,8 @@ public class AdoptionRepository {
MutableLiveData<Resource<AdoptionDTO>> data = new MutableLiveData<>(); MutableLiveData<Resource<AdoptionDTO>> data = new MutableLiveData<>();
data.setValue(Resource.loading(null)); data.setValue(Resource.loading(null));
adoptionApi.getAdoptionById(id).enqueue(new Callback<AdoptionDTO>() { adoptionApi.getAdoptionById(id).enqueue(RetrofitUtils.createSilentCallback(TAG,
@Override result -> data.setValue(Resource.success(result))));
public void onResponse(Call<AdoptionDTO> call, Response<AdoptionDTO> 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<AdoptionDTO> call, Throwable t) {
data.setValue(Resource.error(t.getMessage(), null));
}
});
return data; return data;
} }
@@ -83,21 +55,8 @@ public class AdoptionRepository {
MutableLiveData<Resource<AdoptionDTO>> data = new MutableLiveData<>(); MutableLiveData<Resource<AdoptionDTO>> data = new MutableLiveData<>();
data.setValue(Resource.loading(null)); data.setValue(Resource.loading(null));
adoptionApi.createAdoption(adoption).enqueue(new Callback<AdoptionDTO>() { adoptionApi.createAdoption(adoption).enqueue(RetrofitUtils.createSilentCallback(TAG,
@Override result -> data.setValue(Resource.success(result))));
public void onResponse(Call<AdoptionDTO> call, Response<AdoptionDTO> 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<AdoptionDTO> call, Throwable t) {
data.setValue(Resource.error(t.getMessage(), null));
}
});
return data; return data;
} }
@@ -109,21 +68,8 @@ public class AdoptionRepository {
MutableLiveData<Resource<AdoptionDTO>> data = new MutableLiveData<>(); MutableLiveData<Resource<AdoptionDTO>> data = new MutableLiveData<>();
data.setValue(Resource.loading(null)); data.setValue(Resource.loading(null));
adoptionApi.updateAdoption(id, adoption).enqueue(new Callback<AdoptionDTO>() { adoptionApi.updateAdoption(id, adoption).enqueue(RetrofitUtils.createSilentCallback(TAG,
@Override result -> data.setValue(Resource.success(result))));
public void onResponse(Call<AdoptionDTO> call, Response<AdoptionDTO> 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<AdoptionDTO> call, Throwable t) {
data.setValue(Resource.error(t.getMessage(), null));
}
});
return data; return data;
} }
@@ -135,21 +81,8 @@ public class AdoptionRepository {
MutableLiveData<Resource<Void>> data = new MutableLiveData<>(); MutableLiveData<Resource<Void>> data = new MutableLiveData<>();
data.setValue(Resource.loading(null)); data.setValue(Resource.loading(null));
adoptionApi.deleteAdoption(id).enqueue(new Callback<Void>() { adoptionApi.deleteAdoption(id).enqueue(RetrofitUtils.createSilentCallback(TAG,
@Override result -> data.setValue(Resource.success(null))));
public void onResponse(Call<Void> call, Response<Void> response) {
if (response.isSuccessful()) {
data.setValue(Resource.success(null));
} else {
data.setValue(Resource.error("Error: " + response.message(), null));
}
}
@Override
public void onFailure(Call<Void> call, Throwable t) {
data.setValue(Resource.error(t.getMessage(), null));
}
});
return data; return data;
} }

View File

@@ -7,16 +7,14 @@ import com.example.petstoremobile.api.AppointmentApi;
import com.example.petstoremobile.dtos.AppointmentDTO; import com.example.petstoremobile.dtos.AppointmentDTO;
import com.example.petstoremobile.dtos.PageResponse; import com.example.petstoremobile.dtos.PageResponse;
import com.example.petstoremobile.utils.Resource; import com.example.petstoremobile.utils.Resource;
import com.example.petstoremobile.utils.RetrofitUtils;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
@Singleton @Singleton
public class AppointmentRepository { public class AppointmentRepository {
private static final String TAG = "AppointmentRepository";
private final AppointmentApi appointmentApi; private final AppointmentApi appointmentApi;
@Inject @Inject
@@ -31,21 +29,8 @@ public class AppointmentRepository {
MutableLiveData<Resource<PageResponse<AppointmentDTO>>> data = new MutableLiveData<>(); MutableLiveData<Resource<PageResponse<AppointmentDTO>>> data = new MutableLiveData<>();
data.setValue(Resource.loading(null)); data.setValue(Resource.loading(null));
appointmentApi.getAllAppointments(page, size).enqueue(new Callback<PageResponse<AppointmentDTO>>() { appointmentApi.getAllAppointments(page, size).enqueue(RetrofitUtils.createSilentCallback(TAG,
@Override result -> data.setValue(Resource.success(result))));
public void onResponse(Call<PageResponse<AppointmentDTO>> call, Response<PageResponse<AppointmentDTO>> 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<PageResponse<AppointmentDTO>> call, Throwable t) {
data.setValue(Resource.error(t.getMessage(), null));
}
});
return data; return data;
} }
@@ -57,21 +42,8 @@ public class AppointmentRepository {
MutableLiveData<Resource<AppointmentDTO>> data = new MutableLiveData<>(); MutableLiveData<Resource<AppointmentDTO>> data = new MutableLiveData<>();
data.setValue(Resource.loading(null)); data.setValue(Resource.loading(null));
appointmentApi.getAppointmentById(id).enqueue(new Callback<AppointmentDTO>() { appointmentApi.getAppointmentById(id).enqueue(RetrofitUtils.createSilentCallback(TAG,
@Override result -> data.setValue(Resource.success(result))));
public void onResponse(Call<AppointmentDTO> call, Response<AppointmentDTO> 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<AppointmentDTO> call, Throwable t) {
data.setValue(Resource.error(t.getMessage(), null));
}
});
return data; return data;
} }
@@ -83,21 +55,8 @@ public class AppointmentRepository {
MutableLiveData<Resource<AppointmentDTO>> data = new MutableLiveData<>(); MutableLiveData<Resource<AppointmentDTO>> data = new MutableLiveData<>();
data.setValue(Resource.loading(null)); data.setValue(Resource.loading(null));
appointmentApi.createAppointment(appointment).enqueue(new Callback<AppointmentDTO>() { appointmentApi.createAppointment(appointment).enqueue(RetrofitUtils.createSilentCallback(TAG,
@Override result -> data.setValue(Resource.success(result))));
public void onResponse(Call<AppointmentDTO> call, Response<AppointmentDTO> 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<AppointmentDTO> call, Throwable t) {
data.setValue(Resource.error(t.getMessage(), null));
}
});
return data; return data;
} }
@@ -109,21 +68,8 @@ public class AppointmentRepository {
MutableLiveData<Resource<AppointmentDTO>> data = new MutableLiveData<>(); MutableLiveData<Resource<AppointmentDTO>> data = new MutableLiveData<>();
data.setValue(Resource.loading(null)); data.setValue(Resource.loading(null));
appointmentApi.updateAppointment(id, appointment).enqueue(new Callback<AppointmentDTO>() { appointmentApi.updateAppointment(id, appointment).enqueue(RetrofitUtils.createSilentCallback(TAG,
@Override result -> data.setValue(Resource.success(result))));
public void onResponse(Call<AppointmentDTO> call, Response<AppointmentDTO> 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<AppointmentDTO> call, Throwable t) {
data.setValue(Resource.error(t.getMessage(), null));
}
});
return data; return data;
} }
@@ -135,21 +81,8 @@ public class AppointmentRepository {
MutableLiveData<Resource<Void>> data = new MutableLiveData<>(); MutableLiveData<Resource<Void>> data = new MutableLiveData<>();
data.setValue(Resource.loading(null)); data.setValue(Resource.loading(null));
appointmentApi.deleteAppointment(id).enqueue(new Callback<Void>() { appointmentApi.deleteAppointment(id).enqueue(RetrofitUtils.createSilentCallback(TAG,
@Override result -> data.setValue(Resource.success(null))));
public void onResponse(Call<Void> call, Response<Void> response) {
if (response.isSuccessful()) {
data.setValue(Resource.success(null));
} else {
data.setValue(Resource.error("Error: " + response.message(), null));
}
}
@Override
public void onFailure(Call<Void> call, Throwable t) {
data.setValue(Resource.error(t.getMessage(), null));
}
});
return data; return data;
} }

View File

@@ -1,5 +1,7 @@
package com.example.petstoremobile.repositories; package com.example.petstoremobile.repositories;
import android.util.Log;
import androidx.lifecycle.LiveData; import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData; 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.AuthDTO;
import com.example.petstoremobile.dtos.UserDTO; import com.example.petstoremobile.dtos.UserDTO;
import com.example.petstoremobile.utils.Resource; import com.example.petstoremobile.utils.Resource;
import com.example.petstoremobile.utils.RetrofitUtils;
import java.util.Map; import java.util.Map;
@@ -15,12 +18,10 @@ import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
import okhttp3.MultipartBody; import okhttp3.MultipartBody;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
@Singleton @Singleton
public class AuthRepository { public class AuthRepository {
private static final String TAG = "AuthRepository";
private final AuthApi authApi; private final AuthApi authApi;
private final TokenManager tokenManager; private final TokenManager tokenManager;
@@ -37,26 +38,14 @@ public class AuthRepository {
MutableLiveData<Resource<AuthDTO.LoginResponse>> data = new MutableLiveData<>(); MutableLiveData<Resource<AuthDTO.LoginResponse>> data = new MutableLiveData<>();
data.setValue(Resource.loading(null)); data.setValue(Resource.loading(null));
authApi.login(loginRequest).enqueue(new Callback<AuthDTO.LoginResponse>() { authApi.login(loginRequest).enqueue(RetrofitUtils.createSilentCallback(TAG, result -> {
@Override if (result != null && result.getToken() != null) {
public void onResponse(Call<AuthDTO.LoginResponse> call, Response<AuthDTO.LoginResponse> response) { tokenManager.saveLoginData(result.getToken(), result.getUsername(), result.getRole());
if (response.isSuccessful() && response.body() != null) { data.setValue(Resource.success(result));
tokenManager.saveLoginData( } else {
response.body().getToken(), data.setValue(Resource.error("Login failed", null));
response.body().getUsername(),
response.body().getRole()
);
data.setValue(Resource.success(response.body()));
} else {
data.setValue(Resource.error("Login failed: " + response.message(), null));
}
} }
}));
@Override
public void onFailure(Call<AuthDTO.LoginResponse> call, Throwable t) {
data.setValue(Resource.error(t.getMessage(), null));
}
});
return data; return data;
} }
@@ -68,21 +57,8 @@ public class AuthRepository {
MutableLiveData<Resource<UserDTO>> data = new MutableLiveData<>(); MutableLiveData<Resource<UserDTO>> data = new MutableLiveData<>();
data.setValue(Resource.loading(null)); data.setValue(Resource.loading(null));
authApi.getMe().enqueue(new Callback<UserDTO>() { authApi.getMe().enqueue(RetrofitUtils.createSilentCallback(TAG,
@Override result -> data.setValue(Resource.success(result))));
public void onResponse(Call<UserDTO> call, Response<UserDTO> 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<UserDTO> call, Throwable t) {
data.setValue(Resource.error(t.getMessage(), null));
}
});
return data; return data;
} }
@@ -94,21 +70,8 @@ public class AuthRepository {
MutableLiveData<Resource<UserDTO>> data = new MutableLiveData<>(); MutableLiveData<Resource<UserDTO>> data = new MutableLiveData<>();
data.setValue(Resource.loading(null)); data.setValue(Resource.loading(null));
authApi.updateMe(updates).enqueue(new Callback<UserDTO>() { authApi.updateMe(updates).enqueue(RetrofitUtils.createSilentCallback(TAG,
@Override result -> data.setValue(Resource.success(result))));
public void onResponse(Call<UserDTO> call, Response<UserDTO> 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<UserDTO> call, Throwable t) {
data.setValue(Resource.error(t.getMessage(), null));
}
});
return data; return data;
} }
@@ -120,21 +83,8 @@ public class AuthRepository {
MutableLiveData<Resource<UserDTO>> data = new MutableLiveData<>(); MutableLiveData<Resource<UserDTO>> data = new MutableLiveData<>();
data.setValue(Resource.loading(null)); data.setValue(Resource.loading(null));
authApi.uploadAvatar(avatar).enqueue(new Callback<UserDTO>() { authApi.uploadAvatar(avatar).enqueue(RetrofitUtils.createSilentCallback(TAG,
@Override result -> data.setValue(Resource.success(result))));
public void onResponse(Call<UserDTO> call, Response<UserDTO> 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<UserDTO> call, Throwable t) {
data.setValue(Resource.error(t.getMessage(), null));
}
});
return data; return data;
} }
@@ -146,21 +96,8 @@ public class AuthRepository {
MutableLiveData<Resource<Void>> data = new MutableLiveData<>(); MutableLiveData<Resource<Void>> data = new MutableLiveData<>();
data.setValue(Resource.loading(null)); data.setValue(Resource.loading(null));
authApi.deleteAvatar().enqueue(new Callback<Void>() { authApi.deleteAvatar().enqueue(RetrofitUtils.createSilentCallback(TAG,
@Override result -> data.setValue(Resource.success(null))));
public void onResponse(Call<Void> call, Response<Void> response) {
if (response.isSuccessful()) {
data.setValue(Resource.success(null));
} else {
data.setValue(Resource.error("Error: " + response.message(), null));
}
}
@Override
public void onFailure(Call<Void> call, Throwable t) {
data.setValue(Resource.error(t.getMessage(), null));
}
});
return data; return data;
} }
@@ -171,4 +108,8 @@ public class AuthRepository {
public void logout() { public void logout() {
tokenManager.clearLoginData(); tokenManager.clearLoginData();
} }
public boolean isLoggedIn() {
return tokenManager.getToken() != null;
}
} }

View File

@@ -7,16 +7,14 @@ import com.example.petstoremobile.api.CategoryApi;
import com.example.petstoremobile.dtos.CategoryDTO; import com.example.petstoremobile.dtos.CategoryDTO;
import com.example.petstoremobile.dtos.PageResponse; import com.example.petstoremobile.dtos.PageResponse;
import com.example.petstoremobile.utils.Resource; import com.example.petstoremobile.utils.Resource;
import com.example.petstoremobile.utils.RetrofitUtils;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
@Singleton @Singleton
public class CategoryRepository { public class CategoryRepository {
private static final String TAG = "CategoryRepository";
private final CategoryApi categoryApi; private final CategoryApi categoryApi;
@Inject @Inject
@@ -31,21 +29,8 @@ public class CategoryRepository {
MutableLiveData<Resource<PageResponse<CategoryDTO>>> data = new MutableLiveData<>(); MutableLiveData<Resource<PageResponse<CategoryDTO>>> data = new MutableLiveData<>();
data.setValue(Resource.loading(null)); data.setValue(Resource.loading(null));
categoryApi.getAllCategories(page, size).enqueue(new Callback<PageResponse<CategoryDTO>>() { categoryApi.getAllCategories(page, size).enqueue(RetrofitUtils.createSilentCallback(TAG,
@Override result -> data.setValue(Resource.success(result))));
public void onResponse(Call<PageResponse<CategoryDTO>> call, Response<PageResponse<CategoryDTO>> 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<PageResponse<CategoryDTO>> call, Throwable t) {
data.setValue(Resource.error(t.getMessage(), null));
}
});
return data; return data;
} }

View File

@@ -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<Resource<PageResponse<CustomerDTO>>> getAllCustomers(int page, int size) {
MutableLiveData<Resource<PageResponse<CustomerDTO>>> 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<Resource<CustomerDTO>> getCustomerById(Long id) {
MutableLiveData<Resource<CustomerDTO>> data = new MutableLiveData<>();
data.setValue(Resource.loading(null));
customerApi.getCustomerById(id).enqueue(RetrofitUtils.createSilentCallback(TAG,
result -> data.setValue(Resource.success(result))));
return data;
}
}

View File

@@ -9,16 +9,16 @@ import com.example.petstoremobile.dtos.InventoryDTO;
import com.example.petstoremobile.dtos.InventoryRequest; import com.example.petstoremobile.dtos.InventoryRequest;
import com.example.petstoremobile.dtos.PageResponse; import com.example.petstoremobile.dtos.PageResponse;
import com.example.petstoremobile.utils.Resource; import com.example.petstoremobile.utils.Resource;
import com.example.petstoremobile.utils.RetrofitUtils;
import java.util.List;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
@Singleton @Singleton
public class InventoryRepository { public class InventoryRepository {
private static final String TAG = "InventoryRepository";
private final InventoryApi inventoryApi; private final InventoryApi inventoryApi;
@Inject @Inject
@@ -33,21 +33,8 @@ public class InventoryRepository {
MutableLiveData<Resource<PageResponse<InventoryDTO>>> data = new MutableLiveData<>(); MutableLiveData<Resource<PageResponse<InventoryDTO>>> data = new MutableLiveData<>();
data.setValue(Resource.loading(null)); data.setValue(Resource.loading(null));
inventoryApi.getAllInventory(query, page, size, sort).enqueue(new Callback<PageResponse<InventoryDTO>>() { inventoryApi.getAllInventory(query, page, size, sort).enqueue(RetrofitUtils.createSilentCallback(TAG,
@Override result -> data.setValue(Resource.success(result))));
public void onResponse(Call<PageResponse<InventoryDTO>> call, Response<PageResponse<InventoryDTO>> 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<PageResponse<InventoryDTO>> call, Throwable t) {
data.setValue(Resource.error(t.getMessage(), null));
}
});
return data; return data;
} }
@@ -59,21 +46,8 @@ public class InventoryRepository {
MutableLiveData<Resource<InventoryDTO>> data = new MutableLiveData<>(); MutableLiveData<Resource<InventoryDTO>> data = new MutableLiveData<>();
data.setValue(Resource.loading(null)); data.setValue(Resource.loading(null));
inventoryApi.getInventoryById(id).enqueue(new Callback<InventoryDTO>() { inventoryApi.getInventoryById(id).enqueue(RetrofitUtils.createSilentCallback(TAG,
@Override result -> data.setValue(Resource.success(result))));
public void onResponse(Call<InventoryDTO> call, Response<InventoryDTO> 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<InventoryDTO> call, Throwable t) {
data.setValue(Resource.error(t.getMessage(), null));
}
});
return data; return data;
} }
@@ -85,47 +59,18 @@ public class InventoryRepository {
MutableLiveData<Resource<InventoryDTO>> data = new MutableLiveData<>(); MutableLiveData<Resource<InventoryDTO>> data = new MutableLiveData<>();
data.setValue(Resource.loading(null)); data.setValue(Resource.loading(null));
inventoryApi.createInventory(request).enqueue(new Callback<InventoryDTO>() { inventoryApi.createInventory(request).enqueue(RetrofitUtils.createSilentCallback(TAG,
@Override result -> data.setValue(Resource.success(result))));
public void onResponse(Call<InventoryDTO> call, Response<InventoryDTO> 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<InventoryDTO> call, Throwable t) {
data.setValue(Resource.error(t.getMessage(), null));
}
});
return data; return data;
} }
/**
* Sends a request to the API to update an existing inventory record.
*/
public LiveData<Resource<InventoryDTO>> updateInventory(Long id, InventoryRequest request) { public LiveData<Resource<InventoryDTO>> updateInventory(Long id, InventoryRequest request) {
MutableLiveData<Resource<InventoryDTO>> data = new MutableLiveData<>(); MutableLiveData<Resource<InventoryDTO>> data = new MutableLiveData<>();
data.setValue(Resource.loading(null)); data.setValue(Resource.loading(null));
inventoryApi.updateInventory(id, request).enqueue(new Callback<InventoryDTO>() { inventoryApi.updateInventory(id, request).enqueue(RetrofitUtils.createSilentCallback(TAG,
@Override result -> data.setValue(Resource.success(result))));
public void onResponse(Call<InventoryDTO> call, Response<InventoryDTO> 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<InventoryDTO> call, Throwable t) {
data.setValue(Resource.error(t.getMessage(), null));
}
});
return data; return data;
} }
@@ -137,47 +82,18 @@ public class InventoryRepository {
MutableLiveData<Resource<Void>> data = new MutableLiveData<>(); MutableLiveData<Resource<Void>> data = new MutableLiveData<>();
data.setValue(Resource.loading(null)); data.setValue(Resource.loading(null));
inventoryApi.deleteInventory(id).enqueue(new Callback<Void>() { inventoryApi.deleteInventory(id).enqueue(RetrofitUtils.createSilentCallback(TAG,
@Override result -> data.setValue(Resource.success(null))));
public void onResponse(Call<Void> call, Response<Void> response) {
if (response.isSuccessful()) {
data.setValue(Resource.success(null));
} else {
data.setValue(Resource.error("Error: " + response.message(), null));
}
}
@Override
public void onFailure(Call<Void> call, Throwable t) {
data.setValue(Resource.error(t.getMessage(), null));
}
});
return data; return data;
} }
/**
* Sends a request to the API to delete multiple inventory records at once.
*/
public LiveData<Resource<Void>> bulkDeleteInventory(BulkDeleteRequest request) { public LiveData<Resource<Void>> bulkDeleteInventory(BulkDeleteRequest request) {
MutableLiveData<Resource<Void>> data = new MutableLiveData<>(); MutableLiveData<Resource<Void>> data = new MutableLiveData<>();
data.setValue(Resource.loading(null)); data.setValue(Resource.loading(null));
inventoryApi.bulkDeleteInventory(request).enqueue(new Callback<Void>() { inventoryApi.bulkDeleteInventory(request).enqueue(RetrofitUtils.createSilentCallback(TAG,
@Override result -> data.setValue(Resource.success(null))));
public void onResponse(Call<Void> call, Response<Void> response) {
if (response.isSuccessful()) {
data.setValue(Resource.success(null));
} else {
data.setValue(Resource.error("Error: " + response.message(), null));
}
}
@Override
public void onFailure(Call<Void> call, Throwable t) {
data.setValue(Resource.error(t.getMessage(), null));
}
});
return data; return data;
} }

View File

@@ -1,22 +1,22 @@
package com.example.petstoremobile.repositories; package com.example.petstoremobile.repositories;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import com.example.petstoremobile.api.PetApi; import com.example.petstoremobile.api.PetApi;
import com.example.petstoremobile.dtos.PageResponse; import com.example.petstoremobile.dtos.PageResponse;
import com.example.petstoremobile.dtos.PetDTO; import com.example.petstoremobile.dtos.PetDTO;
import com.example.petstoremobile.utils.Resource; import com.example.petstoremobile.utils.Resource;
import com.example.petstoremobile.utils.RetrofitUtils;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
import okhttp3.MultipartBody; import okhttp3.MultipartBody;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
@Singleton @Singleton
public class PetRepository { public class PetRepository {
private static final String TAG = "PetRepository";
private final PetApi petApi; private final PetApi petApi;
@Inject @Inject
@@ -31,21 +31,8 @@ public class PetRepository {
MutableLiveData<Resource<PageResponse<PetDTO>>> data = new MutableLiveData<>(); MutableLiveData<Resource<PageResponse<PetDTO>>> data = new MutableLiveData<>();
data.setValue(Resource.loading(null)); data.setValue(Resource.loading(null));
petApi.getAllPets(page, size).enqueue(new Callback<PageResponse<PetDTO>>() { petApi.getAllPets(page, size).enqueue(RetrofitUtils.createSilentCallback(TAG,
@Override result -> data.setValue(Resource.success(result))));
public void onResponse(Call<PageResponse<PetDTO>> call, Response<PageResponse<PetDTO>> 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<PageResponse<PetDTO>> call, Throwable t) {
data.setValue(Resource.error(t.getMessage(), null));
}
});
return data; return data;
} }
@@ -57,21 +44,8 @@ public class PetRepository {
MutableLiveData<Resource<PetDTO>> data = new MutableLiveData<>(); MutableLiveData<Resource<PetDTO>> data = new MutableLiveData<>();
data.setValue(Resource.loading(null)); data.setValue(Resource.loading(null));
petApi.getPetById(id).enqueue(new Callback<PetDTO>() { petApi.getPetById(id).enqueue(RetrofitUtils.createSilentCallback(TAG,
@Override result -> data.setValue(Resource.success(result))));
public void onResponse(Call<PetDTO> call, Response<PetDTO> 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<PetDTO> call, Throwable t) {
data.setValue(Resource.error(t.getMessage(), null));
}
});
return data; return data;
} }
@@ -83,21 +57,8 @@ public class PetRepository {
MutableLiveData<Resource<PetDTO>> data = new MutableLiveData<>(); MutableLiveData<Resource<PetDTO>> data = new MutableLiveData<>();
data.setValue(Resource.loading(null)); data.setValue(Resource.loading(null));
petApi.createPet(pet).enqueue(new Callback<PetDTO>() { petApi.createPet(pet).enqueue(RetrofitUtils.createSilentCallback(TAG,
@Override result -> data.setValue(Resource.success(result))));
public void onResponse(Call<PetDTO> call, Response<PetDTO> 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<PetDTO> call, Throwable t) {
data.setValue(Resource.error(t.getMessage(), null));
}
});
return data; return data;
} }
@@ -109,21 +70,8 @@ public class PetRepository {
MutableLiveData<Resource<PetDTO>> data = new MutableLiveData<>(); MutableLiveData<Resource<PetDTO>> data = new MutableLiveData<>();
data.setValue(Resource.loading(null)); data.setValue(Resource.loading(null));
petApi.updatePet(id, pet).enqueue(new Callback<PetDTO>() { petApi.updatePet(id, pet).enqueue(RetrofitUtils.createSilentCallback(TAG,
@Override result -> data.setValue(Resource.success(result))));
public void onResponse(Call<PetDTO> call, Response<PetDTO> 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<PetDTO> call, Throwable t) {
data.setValue(Resource.error(t.getMessage(), null));
}
});
return data; return data;
} }
@@ -135,21 +83,8 @@ public class PetRepository {
MutableLiveData<Resource<Void>> data = new MutableLiveData<>(); MutableLiveData<Resource<Void>> data = new MutableLiveData<>();
data.setValue(Resource.loading(null)); data.setValue(Resource.loading(null));
petApi.deletePet(id).enqueue(new Callback<Void>() { petApi.deletePet(id).enqueue(RetrofitUtils.createSilentCallback(TAG,
@Override result -> data.setValue(Resource.success(null))));
public void onResponse(Call<Void> call, Response<Void> response) {
if (response.isSuccessful()) {
data.setValue(Resource.success(null));
} else {
data.setValue(Resource.error("Error: " + response.message(), null));
}
}
@Override
public void onFailure(Call<Void> call, Throwable t) {
data.setValue(Resource.error(t.getMessage(), null));
}
});
return data; return data;
} }
@@ -161,21 +96,8 @@ public class PetRepository {
MutableLiveData<Resource<Void>> data = new MutableLiveData<>(); MutableLiveData<Resource<Void>> data = new MutableLiveData<>();
data.setValue(Resource.loading(null)); data.setValue(Resource.loading(null));
petApi.uploadPetImage(id, image).enqueue(new Callback<Void>() { petApi.uploadPetImage(id, image).enqueue(RetrofitUtils.createSilentCallback(TAG,
@Override result -> data.setValue(Resource.success(null))));
public void onResponse(Call<Void> call, Response<Void> response) {
if (response.isSuccessful()) {
data.setValue(Resource.success(null));
} else {
data.setValue(Resource.error("Error: " + response.message(), null));
}
}
@Override
public void onFailure(Call<Void> call, Throwable t) {
data.setValue(Resource.error(t.getMessage(), null));
}
});
return data; return data;
} }
@@ -187,21 +109,8 @@ public class PetRepository {
MutableLiveData<Resource<Void>> data = new MutableLiveData<>(); MutableLiveData<Resource<Void>> data = new MutableLiveData<>();
data.setValue(Resource.loading(null)); data.setValue(Resource.loading(null));
petApi.deletePetImage(id).enqueue(new Callback<Void>() { petApi.deletePetImage(id).enqueue(RetrofitUtils.createSilentCallback(TAG,
@Override result -> data.setValue(Resource.success(null))));
public void onResponse(Call<Void> call, Response<Void> response) {
if (response.isSuccessful()) {
data.setValue(Resource.success(null));
} else {
data.setValue(Resource.error("Error: " + response.message(), null));
}
}
@Override
public void onFailure(Call<Void> call, Throwable t) {
data.setValue(Resource.error(t.getMessage(), null));
}
});
return data; return data;
} }

View File

@@ -7,17 +7,16 @@ import com.example.petstoremobile.api.ProductApi;
import com.example.petstoremobile.dtos.PageResponse; import com.example.petstoremobile.dtos.PageResponse;
import com.example.petstoremobile.dtos.ProductDTO; import com.example.petstoremobile.dtos.ProductDTO;
import com.example.petstoremobile.utils.Resource; import com.example.petstoremobile.utils.Resource;
import com.example.petstoremobile.utils.RetrofitUtils;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
import okhttp3.MultipartBody; import okhttp3.MultipartBody;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
@Singleton @Singleton
public class ProductRepository { public class ProductRepository {
private static final String TAG = "ProductRepository";
private final ProductApi productApi; private final ProductApi productApi;
@Inject @Inject
@@ -32,21 +31,8 @@ public class ProductRepository {
MutableLiveData<Resource<PageResponse<ProductDTO>>> data = new MutableLiveData<>(); MutableLiveData<Resource<PageResponse<ProductDTO>>> data = new MutableLiveData<>();
data.setValue(Resource.loading(null)); data.setValue(Resource.loading(null));
productApi.getAllProducts(query, page, size).enqueue(new Callback<PageResponse<ProductDTO>>() { productApi.getAllProducts(query, page, size).enqueue(RetrofitUtils.createSilentCallback(TAG,
@Override result -> data.setValue(Resource.success(result))));
public void onResponse(Call<PageResponse<ProductDTO>> call, Response<PageResponse<ProductDTO>> 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<PageResponse<ProductDTO>> call, Throwable t) {
data.setValue(Resource.error(t.getMessage(), null));
}
});
return data; return data;
} }
@@ -58,21 +44,8 @@ public class ProductRepository {
MutableLiveData<Resource<ProductDTO>> data = new MutableLiveData<>(); MutableLiveData<Resource<ProductDTO>> data = new MutableLiveData<>();
data.setValue(Resource.loading(null)); data.setValue(Resource.loading(null));
productApi.getProductById(id).enqueue(new Callback<ProductDTO>() { productApi.getProductById(id).enqueue(RetrofitUtils.createSilentCallback(TAG,
@Override result -> data.setValue(Resource.success(result))));
public void onResponse(Call<ProductDTO> call, Response<ProductDTO> 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<ProductDTO> call, Throwable t) {
data.setValue(Resource.error(t.getMessage(), null));
}
});
return data; return data;
} }
@@ -84,21 +57,8 @@ public class ProductRepository {
MutableLiveData<Resource<ProductDTO>> data = new MutableLiveData<>(); MutableLiveData<Resource<ProductDTO>> data = new MutableLiveData<>();
data.setValue(Resource.loading(null)); data.setValue(Resource.loading(null));
productApi.createProduct(product).enqueue(new Callback<ProductDTO>() { productApi.createProduct(product).enqueue(RetrofitUtils.createSilentCallback(TAG,
@Override result -> data.setValue(Resource.success(result))));
public void onResponse(Call<ProductDTO> call, Response<ProductDTO> 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<ProductDTO> call, Throwable t) {
data.setValue(Resource.error(t.getMessage(), null));
}
});
return data; return data;
} }
@@ -110,21 +70,8 @@ public class ProductRepository {
MutableLiveData<Resource<ProductDTO>> data = new MutableLiveData<>(); MutableLiveData<Resource<ProductDTO>> data = new MutableLiveData<>();
data.setValue(Resource.loading(null)); data.setValue(Resource.loading(null));
productApi.updateProduct(id, product).enqueue(new Callback<ProductDTO>() { productApi.updateProduct(id, product).enqueue(RetrofitUtils.createSilentCallback(TAG,
@Override result -> data.setValue(Resource.success(result))));
public void onResponse(Call<ProductDTO> call, Response<ProductDTO> 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<ProductDTO> call, Throwable t) {
data.setValue(Resource.error(t.getMessage(), null));
}
});
return data; return data;
} }
@@ -136,21 +83,8 @@ public class ProductRepository {
MutableLiveData<Resource<Void>> data = new MutableLiveData<>(); MutableLiveData<Resource<Void>> data = new MutableLiveData<>();
data.setValue(Resource.loading(null)); data.setValue(Resource.loading(null));
productApi.deleteProduct(id).enqueue(new Callback<Void>() { productApi.deleteProduct(id).enqueue(RetrofitUtils.createSilentCallback(TAG,
@Override result -> data.setValue(Resource.success(null))));
public void onResponse(Call<Void> call, Response<Void> response) {
if (response.isSuccessful()) {
data.setValue(Resource.success(null));
} else {
data.setValue(Resource.error("Error: " + response.message(), null));
}
}
@Override
public void onFailure(Call<Void> call, Throwable t) {
data.setValue(Resource.error(t.getMessage(), null));
}
});
return data; return data;
} }
@@ -162,21 +96,8 @@ public class ProductRepository {
MutableLiveData<Resource<Void>> data = new MutableLiveData<>(); MutableLiveData<Resource<Void>> data = new MutableLiveData<>();
data.setValue(Resource.loading(null)); data.setValue(Resource.loading(null));
productApi.uploadProductImage(id, image).enqueue(new Callback<Void>() { productApi.uploadProductImage(id, image).enqueue(RetrofitUtils.createSilentCallback(TAG,
@Override result -> data.setValue(Resource.success(null))));
public void onResponse(Call<Void> call, Response<Void> response) {
if (response.isSuccessful()) {
data.setValue(Resource.success(null));
} else {
data.setValue(Resource.error("Error: " + response.message(), null));
}
}
@Override
public void onFailure(Call<Void> call, Throwable t) {
data.setValue(Resource.error(t.getMessage(), null));
}
});
return data; return data;
} }
@@ -188,21 +109,8 @@ public class ProductRepository {
MutableLiveData<Resource<Void>> data = new MutableLiveData<>(); MutableLiveData<Resource<Void>> data = new MutableLiveData<>();
data.setValue(Resource.loading(null)); data.setValue(Resource.loading(null));
productApi.deleteProductImage(id).enqueue(new Callback<Void>() { productApi.deleteProductImage(id).enqueue(RetrofitUtils.createSilentCallback(TAG,
@Override result -> data.setValue(Resource.success(null))));
public void onResponse(Call<Void> call, Response<Void> response) {
if (response.isSuccessful()) {
data.setValue(Resource.success(null));
} else {
data.setValue(Resource.error("Error: " + response.message(), null));
}
}
@Override
public void onFailure(Call<Void> call, Throwable t) {
data.setValue(Resource.error(t.getMessage(), null));
}
});
return data; return data;
} }

View File

@@ -7,16 +7,14 @@ import com.example.petstoremobile.api.ProductSupplierApi;
import com.example.petstoremobile.dtos.PageResponse; import com.example.petstoremobile.dtos.PageResponse;
import com.example.petstoremobile.dtos.ProductSupplierDTO; import com.example.petstoremobile.dtos.ProductSupplierDTO;
import com.example.petstoremobile.utils.Resource; import com.example.petstoremobile.utils.Resource;
import com.example.petstoremobile.utils.RetrofitUtils;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
@Singleton @Singleton
public class ProductSupplierRepository { public class ProductSupplierRepository {
private static final String TAG = "ProductSupplierRepository";
private final ProductSupplierApi api; private final ProductSupplierApi api;
@Inject @Inject
@@ -31,21 +29,8 @@ public class ProductSupplierRepository {
MutableLiveData<Resource<PageResponse<ProductSupplierDTO>>> data = new MutableLiveData<>(); MutableLiveData<Resource<PageResponse<ProductSupplierDTO>>> data = new MutableLiveData<>();
data.setValue(Resource.loading(null)); data.setValue(Resource.loading(null));
api.getAllProductSuppliers(page, size).enqueue(new Callback<PageResponse<ProductSupplierDTO>>() { api.getAllProductSuppliers(page, size).enqueue(RetrofitUtils.createSilentCallback(TAG,
@Override result -> data.setValue(Resource.success(result))));
public void onResponse(Call<PageResponse<ProductSupplierDTO>> call, Response<PageResponse<ProductSupplierDTO>> 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<PageResponse<ProductSupplierDTO>> call, Throwable t) {
data.setValue(Resource.error(t.getMessage(), null));
}
});
return data; return data;
} }
@@ -57,21 +42,8 @@ public class ProductSupplierRepository {
MutableLiveData<Resource<ProductSupplierDTO>> data = new MutableLiveData<>(); MutableLiveData<Resource<ProductSupplierDTO>> data = new MutableLiveData<>();
data.setValue(Resource.loading(null)); data.setValue(Resource.loading(null));
api.createProductSupplier(dto).enqueue(new Callback<ProductSupplierDTO>() { api.createProductSupplier(dto).enqueue(RetrofitUtils.createSilentCallback(TAG,
@Override result -> data.setValue(Resource.success(result))));
public void onResponse(Call<ProductSupplierDTO> call, Response<ProductSupplierDTO> 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<ProductSupplierDTO> call, Throwable t) {
data.setValue(Resource.error(t.getMessage(), null));
}
});
return data; return data;
} }
@@ -83,21 +55,8 @@ public class ProductSupplierRepository {
MutableLiveData<Resource<ProductSupplierDTO>> data = new MutableLiveData<>(); MutableLiveData<Resource<ProductSupplierDTO>> data = new MutableLiveData<>();
data.setValue(Resource.loading(null)); data.setValue(Resource.loading(null));
api.updateProductSupplier(productId, supplierId, dto).enqueue(new Callback<ProductSupplierDTO>() { api.updateProductSupplier(productId, supplierId, dto).enqueue(RetrofitUtils.createSilentCallback(TAG,
@Override result -> data.setValue(Resource.success(result))));
public void onResponse(Call<ProductSupplierDTO> call, Response<ProductSupplierDTO> 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<ProductSupplierDTO> call, Throwable t) {
data.setValue(Resource.error(t.getMessage(), null));
}
});
return data; return data;
} }
@@ -109,21 +68,8 @@ public class ProductSupplierRepository {
MutableLiveData<Resource<Void>> data = new MutableLiveData<>(); MutableLiveData<Resource<Void>> data = new MutableLiveData<>();
data.setValue(Resource.loading(null)); data.setValue(Resource.loading(null));
api.deleteProductSupplier(productId, supplierId).enqueue(new Callback<Void>() { api.deleteProductSupplier(productId, supplierId).enqueue(RetrofitUtils.createSilentCallback(TAG,
@Override result -> data.setValue(Resource.success(null))));
public void onResponse(Call<Void> call, Response<Void> response) {
if (response.isSuccessful()) {
data.setValue(Resource.success(null));
} else {
data.setValue(Resource.error("Error: " + response.message(), null));
}
}
@Override
public void onFailure(Call<Void> call, Throwable t) {
data.setValue(Resource.error(t.getMessage(), null));
}
});
return data; return data;
} }

View File

@@ -7,6 +7,7 @@ import com.example.petstoremobile.api.PurchaseOrderApi;
import com.example.petstoremobile.dtos.PageResponse; import com.example.petstoremobile.dtos.PageResponse;
import com.example.petstoremobile.dtos.PurchaseOrderDTO; import com.example.petstoremobile.dtos.PurchaseOrderDTO;
import com.example.petstoremobile.utils.Resource; import com.example.petstoremobile.utils.Resource;
import com.example.petstoremobile.utils.RetrofitUtils;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
@@ -17,6 +18,7 @@ import retrofit2.Response;
@Singleton @Singleton
public class PurchaseOrderRepository { public class PurchaseOrderRepository {
private static final String TAG = "PurchaseOrderRepo";
private final PurchaseOrderApi api; private final PurchaseOrderApi api;
@Inject @Inject
@@ -31,21 +33,9 @@ public class PurchaseOrderRepository {
MutableLiveData<Resource<PageResponse<PurchaseOrderDTO>>> data = new MutableLiveData<>(); MutableLiveData<Resource<PageResponse<PurchaseOrderDTO>>> data = new MutableLiveData<>();
data.setValue(Resource.loading(null)); data.setValue(Resource.loading(null));
api.getAllPurchaseOrders(page, size).enqueue(new Callback<PageResponse<PurchaseOrderDTO>>() { api.getAllPurchaseOrders(page, size).enqueue(RetrofitUtils.createSilentCallback(TAG, result -> {
@Override data.setValue(Resource.success(result));
public void onResponse(Call<PageResponse<PurchaseOrderDTO>> call, Response<PageResponse<PurchaseOrderDTO>> 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<PageResponse<PurchaseOrderDTO>> call, Throwable t) {
data.setValue(Resource.error(t.getMessage(), null));
}
});
return data; return data;
} }
@@ -57,21 +47,9 @@ public class PurchaseOrderRepository {
MutableLiveData<Resource<PurchaseOrderDTO>> data = new MutableLiveData<>(); MutableLiveData<Resource<PurchaseOrderDTO>> data = new MutableLiveData<>();
data.setValue(Resource.loading(null)); data.setValue(Resource.loading(null));
api.getPurchaseOrderById(id).enqueue(new Callback<PurchaseOrderDTO>() { api.getPurchaseOrderById(id).enqueue(RetrofitUtils.createSilentCallback(TAG, result -> {
@Override data.setValue(Resource.success(result));
public void onResponse(Call<PurchaseOrderDTO> call, Response<PurchaseOrderDTO> 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<PurchaseOrderDTO> call, Throwable t) {
data.setValue(Resource.error(t.getMessage(), null));
}
});
return data; return data;
} }

View File

@@ -7,16 +7,14 @@ import com.example.petstoremobile.api.ServiceApi;
import com.example.petstoremobile.dtos.PageResponse; import com.example.petstoremobile.dtos.PageResponse;
import com.example.petstoremobile.dtos.ServiceDTO; import com.example.petstoremobile.dtos.ServiceDTO;
import com.example.petstoremobile.utils.Resource; import com.example.petstoremobile.utils.Resource;
import com.example.petstoremobile.utils.RetrofitUtils;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
@Singleton @Singleton
public class ServiceRepository { public class ServiceRepository {
private static final String TAG = "ServiceRepository";
private final ServiceApi serviceApi; private final ServiceApi serviceApi;
@Inject @Inject
@@ -31,21 +29,8 @@ public class ServiceRepository {
MutableLiveData<Resource<PageResponse<ServiceDTO>>> data = new MutableLiveData<>(); MutableLiveData<Resource<PageResponse<ServiceDTO>>> data = new MutableLiveData<>();
data.setValue(Resource.loading(null)); data.setValue(Resource.loading(null));
serviceApi.getAllServices(page, size).enqueue(new Callback<PageResponse<ServiceDTO>>() { serviceApi.getAllServices(page, size).enqueue(RetrofitUtils.createSilentCallback(TAG,
@Override result -> data.setValue(Resource.success(result))));
public void onResponse(Call<PageResponse<ServiceDTO>> call, Response<PageResponse<ServiceDTO>> 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<PageResponse<ServiceDTO>> call, Throwable t) {
data.setValue(Resource.error(t.getMessage(), null));
}
});
return data; return data;
} }
@@ -57,21 +42,8 @@ public class ServiceRepository {
MutableLiveData<Resource<ServiceDTO>> data = new MutableLiveData<>(); MutableLiveData<Resource<ServiceDTO>> data = new MutableLiveData<>();
data.setValue(Resource.loading(null)); data.setValue(Resource.loading(null));
serviceApi.getServiceById(id).enqueue(new Callback<ServiceDTO>() { serviceApi.getServiceById(id).enqueue(RetrofitUtils.createSilentCallback(TAG,
@Override result -> data.setValue(Resource.success(result))));
public void onResponse(Call<ServiceDTO> call, Response<ServiceDTO> 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<ServiceDTO> call, Throwable t) {
data.setValue(Resource.error(t.getMessage(), null));
}
});
return data; return data;
} }
@@ -83,21 +55,8 @@ public class ServiceRepository {
MutableLiveData<Resource<ServiceDTO>> data = new MutableLiveData<>(); MutableLiveData<Resource<ServiceDTO>> data = new MutableLiveData<>();
data.setValue(Resource.loading(null)); data.setValue(Resource.loading(null));
serviceApi.createService(service).enqueue(new Callback<ServiceDTO>() { serviceApi.createService(service).enqueue(RetrofitUtils.createSilentCallback(TAG,
@Override result -> data.setValue(Resource.success(result))));
public void onResponse(Call<ServiceDTO> call, Response<ServiceDTO> 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<ServiceDTO> call, Throwable t) {
data.setValue(Resource.error(t.getMessage(), null));
}
});
return data; return data;
} }
@@ -109,21 +68,8 @@ public class ServiceRepository {
MutableLiveData<Resource<ServiceDTO>> data = new MutableLiveData<>(); MutableLiveData<Resource<ServiceDTO>> data = new MutableLiveData<>();
data.setValue(Resource.loading(null)); data.setValue(Resource.loading(null));
serviceApi.updateService(id, service).enqueue(new Callback<ServiceDTO>() { serviceApi.updateService(id, service).enqueue(RetrofitUtils.createSilentCallback(TAG,
@Override result -> data.setValue(Resource.success(result))));
public void onResponse(Call<ServiceDTO> call, Response<ServiceDTO> 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<ServiceDTO> call, Throwable t) {
data.setValue(Resource.error(t.getMessage(), null));
}
});
return data; return data;
} }
@@ -135,21 +81,8 @@ public class ServiceRepository {
MutableLiveData<Resource<Void>> data = new MutableLiveData<>(); MutableLiveData<Resource<Void>> data = new MutableLiveData<>();
data.setValue(Resource.loading(null)); data.setValue(Resource.loading(null));
serviceApi.deleteService(id).enqueue(new Callback<Void>() { serviceApi.deleteService(id).enqueue(RetrofitUtils.createSilentCallback(TAG,
@Override result -> data.setValue(Resource.success(null))));
public void onResponse(Call<Void> call, Response<Void> response) {
if (response.isSuccessful()) {
data.setValue(Resource.success(null));
} else {
data.setValue(Resource.error("Error: " + response.message(), null));
}
}
@Override
public void onFailure(Call<Void> call, Throwable t) {
data.setValue(Resource.error(t.getMessage(), null));
}
});
return data; return data;
} }

View File

@@ -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<Resource<PageResponse<StoreDTO>>> getAllStores(int page, int size) {
MutableLiveData<Resource<PageResponse<StoreDTO>>> data = new MutableLiveData<>();
data.setValue(Resource.loading(null));
storeApi.getAllStores(page, size).enqueue(RetrofitUtils.createSilentCallback(TAG,
result -> data.setValue(Resource.success(result))));
return data;
}
}

View File

@@ -7,16 +7,14 @@ import com.example.petstoremobile.api.SupplierApi;
import com.example.petstoremobile.dtos.PageResponse; import com.example.petstoremobile.dtos.PageResponse;
import com.example.petstoremobile.dtos.SupplierDTO; import com.example.petstoremobile.dtos.SupplierDTO;
import com.example.petstoremobile.utils.Resource; import com.example.petstoremobile.utils.Resource;
import com.example.petstoremobile.utils.RetrofitUtils;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
@Singleton @Singleton
public class SupplierRepository { public class SupplierRepository {
private static final String TAG = "SupplierRepository";
private final SupplierApi supplierApi; private final SupplierApi supplierApi;
@Inject @Inject
@@ -31,21 +29,8 @@ public class SupplierRepository {
MutableLiveData<Resource<PageResponse<SupplierDTO>>> data = new MutableLiveData<>(); MutableLiveData<Resource<PageResponse<SupplierDTO>>> data = new MutableLiveData<>();
data.setValue(Resource.loading(null)); data.setValue(Resource.loading(null));
supplierApi.getAllSuppliers(page, size).enqueue(new Callback<PageResponse<SupplierDTO>>() { supplierApi.getAllSuppliers(page, size).enqueue(RetrofitUtils.createSilentCallback(TAG,
@Override result -> data.setValue(Resource.success(result))));
public void onResponse(Call<PageResponse<SupplierDTO>> call, Response<PageResponse<SupplierDTO>> 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<PageResponse<SupplierDTO>> call, Throwable t) {
data.setValue(Resource.error(t.getMessage(), null));
}
});
return data; return data;
} }
@@ -57,21 +42,8 @@ public class SupplierRepository {
MutableLiveData<Resource<SupplierDTO>> data = new MutableLiveData<>(); MutableLiveData<Resource<SupplierDTO>> data = new MutableLiveData<>();
data.setValue(Resource.loading(null)); data.setValue(Resource.loading(null));
supplierApi.getSupplierById(id).enqueue(new Callback<SupplierDTO>() { supplierApi.getSupplierById(id).enqueue(RetrofitUtils.createSilentCallback(TAG,
@Override result -> data.setValue(Resource.success(result))));
public void onResponse(Call<SupplierDTO> call, Response<SupplierDTO> 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<SupplierDTO> call, Throwable t) {
data.setValue(Resource.error(t.getMessage(), null));
}
});
return data; return data;
} }
@@ -83,21 +55,8 @@ public class SupplierRepository {
MutableLiveData<Resource<SupplierDTO>> data = new MutableLiveData<>(); MutableLiveData<Resource<SupplierDTO>> data = new MutableLiveData<>();
data.setValue(Resource.loading(null)); data.setValue(Resource.loading(null));
supplierApi.createSupplier(supplier).enqueue(new Callback<SupplierDTO>() { supplierApi.createSupplier(supplier).enqueue(RetrofitUtils.createSilentCallback(TAG,
@Override result -> data.setValue(Resource.success(result))));
public void onResponse(Call<SupplierDTO> call, Response<SupplierDTO> 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<SupplierDTO> call, Throwable t) {
data.setValue(Resource.error(t.getMessage(), null));
}
});
return data; return data;
} }
@@ -106,26 +65,15 @@ public class SupplierRepository {
* Sends a request to the API to update an existing supplier record by ID. * Sends a request to the API to update an existing supplier record by ID.
*/ */
public LiveData<Resource<SupplierDTO>> updateSupplier(Long id, SupplierDTO supplier) { public LiveData<Resource<SupplierDTO>> updateSupplier(Long id, SupplierDTO supplier) {
MutableLiveData<Resource<SupplierDTO>> data = new MutableLiveData<>(); MutableLiveData<Resource<Resource<SupplierDTO>>> data = new MutableLiveData<>();
data.setValue(Resource.loading(null)); // Note: The original return type was LiveData<Resource<SupplierDTO>>, fixing here
MutableLiveData<Resource<SupplierDTO>> resultData = new MutableLiveData<>();
resultData.setValue(Resource.loading(null));
supplierApi.updateSupplier(id, supplier).enqueue(new Callback<SupplierDTO>() { supplierApi.updateSupplier(id, supplier).enqueue(RetrofitUtils.createSilentCallback(TAG,
@Override result -> resultData.setValue(Resource.success(result))));
public void onResponse(Call<SupplierDTO> call, Response<SupplierDTO> response) {
if (response.isSuccessful() && response.body() != null) {
data.setValue(Resource.success(response.body()));
} else {
data.setValue(Resource.error("Error: " + response.message(), null));
}
}
@Override return resultData;
public void onFailure(Call<SupplierDTO> call, Throwable t) {
data.setValue(Resource.error(t.getMessage(), null));
}
});
return data;
} }
/** /**
@@ -135,21 +83,8 @@ public class SupplierRepository {
MutableLiveData<Resource<Void>> data = new MutableLiveData<>(); MutableLiveData<Resource<Void>> data = new MutableLiveData<>();
data.setValue(Resource.loading(null)); data.setValue(Resource.loading(null));
supplierApi.deleteSupplier(id).enqueue(new Callback<Void>() { supplierApi.deleteSupplier(id).enqueue(RetrofitUtils.createSilentCallback(TAG,
@Override result -> data.setValue(Resource.success(null))));
public void onResponse(Call<Void> call, Response<Void> response) {
if (response.isSuccessful()) {
data.setValue(Resource.success(null));
} else {
data.setValue(Resource.error("Error: " + response.message(), null));
}
}
@Override
public void onFailure(Call<Void> call, Throwable t) {
data.setValue(Resource.error(t.getMessage(), null));
}
});
return data; return data;
} }

View File

@@ -14,6 +14,7 @@ import com.example.petstoremobile.dtos.CustomerDTO;
import com.example.petstoremobile.dtos.MessageDTO; import com.example.petstoremobile.dtos.MessageDTO;
import com.example.petstoremobile.dtos.PageResponse; import com.example.petstoremobile.dtos.PageResponse;
import com.example.petstoremobile.utils.NotificationHelper; import com.example.petstoremobile.utils.NotificationHelper;
import com.example.petstoremobile.utils.RetrofitUtils;
import com.example.petstoremobile.websocket.StompChatManager; import com.example.petstoremobile.websocket.StompChatManager;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
@@ -63,54 +64,31 @@ public class ChatNotificationService extends Service {
currentUserId = tokenManager.getUserId(); currentUserId = tokenManager.getUserId();
if (token != null && stompChatManager == null) { if (token != null && stompChatManager == null) {
customerApi.getAllCustomers(0, 1000).enqueue(new Callback<PageResponse<CustomerDTO>>() { customerApi.getAllCustomers(0, 1000).enqueue(RetrofitUtils.createSilentCallback(TAG, result -> {
@Override for (CustomerDTO customer : result.getContent()) {
public void onResponse(@NonNull Call<PageResponse<CustomerDTO>> call, @NonNull Response<PageResponse<CustomerDTO>> response) { customerIdToName.put(customer.getCustomerId(), customer.getFullName());
if (response.isSuccessful() && response.body() != null) {
for (CustomerDTO customer : response.body().getContent()) {
customerIdToName.put(customer.getCustomerId(), customer.getFullName());
}
}
loadConversationsAndStartStomp(token, role);
} }
loadConversationsAndStartStomp(token, role);
@Override }));
public void onFailure(@NonNull Call<PageResponse<CustomerDTO>> call, @NonNull Throwable t) {
Log.e(TAG, "Failed to load customers", t);
loadConversationsAndStartStomp(token, role);
}
});
} }
} }
private void loadConversationsAndStartStomp(String token, String role) { private void loadConversationsAndStartStomp(String token, String role) {
// Fetch existing conversations // Fetch existing conversations
chatApi.getAllConversations().enqueue(new Callback<List<ConversationDTO>>() { chatApi.getAllConversations().enqueue(RetrofitUtils.createSilentCallback(TAG, result -> {
@Override for (ConversationDTO conversation : result) {
public void onResponse(@NonNull Call<List<ConversationDTO>> call, @NonNull Response<List<ConversationDTO>> response) { if (conversation.getId() != null) {
if (response.isSuccessful() && response.body() != null) { knownConversationIds.add(conversation.getId());
for (ConversationDTO conversation : response.body()) { conversationToCustomerId.put(conversation.getId(), conversation.getCustomerId());
if (conversation.getId() != null) { // subscribe to existing conversations to get message notifications
knownConversationIds.add(conversation.getId()); if (stompChatManager != null) {
conversationToCustomerId.put(conversation.getId(), conversation.getCustomerId()); stompChatManager.subscribeToConversation(conversation.getId());
// 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);
} }
Log.d(TAG, "Loaded " + knownConversationIds.size() + " existing conversations");
@Override startStomp(token, role);
public void onFailure(@NonNull Call<List<ConversationDTO>> call, @NonNull Throwable t) { }));
Log.e(TAG, "Failed to load existing conversations", t);
//tries to connect if loading fails
startStomp(token, role);
}
});
} }
private void startStomp(String token, String 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 // Helper function to fetch customer name for a conversation
private void fetchCustomerName(Long customerId) { private void fetchCustomerName(Long customerId) {
customerApi.getCustomerById(customerId).enqueue(new Callback<CustomerDTO>() { customerApi.getCustomerById(customerId).enqueue(RetrofitUtils.createSilentCallback(TAG, result -> {
@Override customerIdToName.put(customerId, result.getFullName());
public void onResponse(@NonNull Call<CustomerDTO> call, @NonNull Response<CustomerDTO> response) { }));
if (response.isSuccessful() && response.body() != null) {
customerIdToName.put(customerId, response.body().getFullName());
}
}
@Override
public void onFailure(@NonNull Call<CustomerDTO> call, @NonNull Throwable t) {
Log.e(TAG, "Failed to fetch customer name", t);
}
});
} }
//When the service is destroyed, disconnect from the websocket //When the service is destroyed, disconnect from the websocket
@@ -228,4 +196,4 @@ public class ChatNotificationService extends Service {
public IBinder onBind(Intent intent) { public IBinder onBind(Intent intent) {
return null; return null;
} }
} }

View File

@@ -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 <T> The type of the response body.
*/
public interface SuccessCallback<T> {
void onSuccess(T result);
}
/**
* Creates a callback for Retrofit calls that handles errors and logging.
*/
public static <T> Callback<T> createCallback(Context context, String tag, String successMsg, SuccessCallback<T> successCallback) {
return new Callback<T>() {
@Override
public void onResponse(@NonNull Call<T> call, @NonNull Response<T> 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<T> 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 <T> Callback<T> createSilentCallback(String tag, SuccessCallback<T> successCallback) {
return new Callback<T>() {
@Override
public void onResponse(@NonNull Call<T> call, @NonNull Response<T> response) {
if (response.isSuccessful() && successCallback != null) {
successCallback.onSuccess(response.body());
} else {
Log.e(tag, "API Error: " + response.code());
}
}
@Override
public void onFailure(@NonNull Call<T> call, @NonNull Throwable t) {
Log.e(tag, "Network Error: " + t.getMessage());
}
};
}
}

View File

@@ -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<Resource<PageResponse<CustomerDTO>>> getAllCustomers(int page, int size) {
return repository.getAllCustomers(page, size);
}
/**
* Retrieves a single customer by their ID.
*/
public LiveData<Resource<CustomerDTO>> getCustomerById(Long id) {
return repository.getCustomerById(id);
}
}

View File

@@ -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<Resource<PageResponse<StoreDTO>>> getAllStores(int page, int size) {
return repository.getAllStores(page, size);
}
}