From 52892a731c6a898c040889a87b47fc3f01031953 Mon Sep 17 00:00:00 2001 From: Alex <78383757+Lextical@users.noreply.github.com> Date: Sun, 19 Apr 2026 20:18:28 -0600 Subject: [PATCH] added comments to android --- .../activities/ForgotPasswordActivity.java | 7 ++ .../activities/HomeActivity.java | 4 +- .../activities/MainActivity.java | 5 +- .../adapters/ActivityLogAdapter.java | 27 +++++ .../adapters/AdoptionAdapter.java | 18 +++ .../adapters/AppointmentAdapter.java | 24 ++++ .../adapters/BlackTextArrayAdapter.java | 1 + .../petstoremobile/adapters/ChatAdapter.java | 18 +++ .../adapters/CouponAdapter.java | 24 ++++ .../adapters/CustomerAdapter.java | 25 +++++ .../adapters/EmployeeAdapter.java | 24 ++++ .../adapters/InventoryAdapter.java | 25 ++++- .../adapters/MessageAdapter.java | 66 ++++++++++- .../petstoremobile/adapters/PetAdapter.java | 36 +++++- .../adapters/ProductAdapter.java | 24 ++++ .../adapters/ProductSupplierAdapter.java | 21 ++++ .../adapters/PurchaseOrderAdapter.java | 15 +++ .../petstoremobile/adapters/SaleAdapter.java | 15 +++ .../adapters/ServiceAdapter.java | 22 +++- .../adapters/SupplierAdapter.java | 25 ++++- .../adapters/WhiteTextArrayAdapter.java | 5 +- .../petstoremobile/api/ActivityLogApi.java | 2 + .../petstoremobile/api/AdoptionApi.java | 7 ++ .../petstoremobile/api/AppointmentApi.java | 9 +- .../petstoremobile/api/CategoryApi.java | 2 + .../example/petstoremobile/api/ChatApi.java | 5 +- .../petstoremobile/api/CustomerApi.java | 7 ++ .../petstoremobile/api/EmployeeApi.java | 12 +- .../petstoremobile/api/InventoryApi.java | 12 +- .../petstoremobile/api/MessageApi.java | 6 +- .../example/petstoremobile/api/PetApi.java | 8 +- .../petstoremobile/api/ProductApi.java | 13 ++- .../api/ProductSupplierApi.java | 10 +- .../petstoremobile/api/PurchaseOrderApi.java | 3 + .../example/petstoremobile/api/RefundApi.java | 6 + .../example/petstoremobile/api/SaleApi.java | 4 + .../petstoremobile/api/ServiceApi.java | 2 +- .../example/petstoremobile/api/StoreApi.java | 4 + .../example/petstoremobile/api/UserApi.java | 3 + .../petstoremobile/api/auth/TokenManager.java | 1 + .../petstoremobile/dtos/ActivityLogDTO.java | 3 + .../petstoremobile/dtos/AdoptionDTO.java | 3 + .../petstoremobile/dtos/AppointmentDTO.java | 3 + .../example/petstoremobile/dtos/AuthDTO.java | 4 +- .../dtos/AvatarUploadResponse.java | 3 + .../dtos/BulkDeleteRequest.java | 3 + .../petstoremobile/dtos/CategoryDTO.java | 3 + .../petstoremobile/dtos/ConversationDTO.java | 3 + .../petstoremobile/dtos/CouponDTO.java | 3 + .../petstoremobile/dtos/CustomerDTO.java | 3 + .../petstoremobile/dtos/DropdownDTO.java | 3 + .../petstoremobile/dtos/EmployeeDTO.java | 3 + .../petstoremobile/dtos/ErrorResponse.java | 5 +- .../petstoremobile/dtos/InventoryDTO.java | 3 + .../petstoremobile/dtos/MessageDTO.java | 3 + .../petstoremobile/dtos/PageResponse.java | 4 +- .../example/petstoremobile/dtos/PetDTO.java | 3 + .../petstoremobile/dtos/ProductDTO.java | 3 + .../dtos/ProductSupplierDTO.java | 3 + .../petstoremobile/dtos/PurchaseOrderDTO.java | 3 + .../petstoremobile/dtos/RefundDTO.java | 3 + .../example/petstoremobile/dtos/SaleDTO.java | 3 + .../dtos/SendMessageRequest.java | 3 + .../petstoremobile/dtos/ServiceDTO.java | 3 + .../example/petstoremobile/dtos/StoreDTO.java | 3 + .../petstoremobile/dtos/SupplierDTO.java | 3 + .../dtos/UpdateConversationStatusRequest.java | 3 + .../example/petstoremobile/dtos/UserDTO.java | 3 + .../fragments/ChatFragment.java | 81 +++++++++++++ .../fragments/ListFragment.java | 7 +- .../fragments/ProfileFragment.java | 6 + .../listfragments/ActivityLogFragment.java | 27 +++++ .../listfragments/AdoptionFragment.java | 63 +++++++++++ .../listfragments/AnalyticsFragment.java | 61 +++++++++- .../listfragments/AppointmentFragment.java | 69 ++++++++++++ .../listfragments/CouponFragment.java | 39 +++++++ .../listfragments/CustomerFragment.java | 33 ++++++ .../listfragments/InventoryFragment.java | 51 +++++++++ .../fragments/listfragments/PetFragment.java | 60 ++++++++++ .../listfragments/ProductFragment.java | 42 +++++++ .../ProductSupplierFragment.java | 51 +++++++++ .../listfragments/PurchaseOrderFragment.java | 45 ++++++++ .../fragments/listfragments/SaleFragment.java | 54 +++++++++ .../listfragments/ServiceFragment.java | 39 +++++++ .../listfragments/StaffFragment.java | 36 ++++++ .../listfragments/SupplierFragment.java | 42 +++++++ .../AdoptionDetailFragment.java | 49 ++++++++ .../AppointmentDetailFragment.java | 64 +++++++++++ .../detailfragments/CouponDetailFragment.java | 21 ++++ .../CustomerDetailFragment.java | 30 +++++ .../InventoryDetailFragment.java | 48 ++++++++ .../ProductDetailFragment.java | 45 ++++++++ .../ProductSupplierDetailFragment.java | 39 +++++++ .../PurchaseOrderDetailFragment.java | 15 +++ .../detailfragments/RefundFragment.java | 53 ++++++++- .../detailfragments/SaleDetailFragment.java | 60 ++++++++++ .../ServiceDetailFragment.java | 39 +++++++ .../detailfragments/StaffDetailFragment.java | 39 +++++++ .../SupplierDetailFragment.java | 39 +++++++ .../PetProfileFragment.java | 27 +++++ .../example/petstoremobile/models/Chat.java | 3 + .../petstoremobile/models/Message.java | 3 + .../example/petstoremobile/models/Sale.java | 3 + .../repositories/ActivityLogRepository.java | 6 + .../repositories/AdoptionRepository.java | 3 + .../repositories/AppointmentRepository.java | 3 + .../repositories/AuthRepository.java | 3 + .../repositories/BaseRepository.java | 2 +- .../repositories/CategoryRepository.java | 3 + .../repositories/ChatRepository.java | 2 +- .../repositories/CouponRepository.java | 3 + .../repositories/CustomerRepository.java | 3 + .../repositories/EmployeeRepository.java | 3 + .../repositories/InventoryRepository.java | 3 + .../repositories/PetRepository.java | 3 + .../repositories/ProductRepository.java | 3 + .../ProductSupplierRepository.java | 3 + .../repositories/PurchaseOrderRepository.java | 3 + .../repositories/SaleRepository.java | 3 + .../repositories/ServiceRepository.java | 3 + .../repositories/StoreRepository.java | 3 + .../repositories/SupplierRepository.java | 3 + .../repositories/UserRepository.java | 3 + .../services/ChatNotificationService.java | 4 +- .../petstoremobile/utils/EventDecorator.java | 6 + .../petstoremobile/utils/FileUtils.java | 10 ++ .../petstoremobile/utils/SelectionHelper.java | 34 +++++- .../petstoremobile/utils/SpinnerUtils.java | 7 +- .../viewmodels/ActivityLogListViewModel.java | 39 +++++++ .../viewmodels/AdoptionDetailViewModel.java | 74 +++++++++++- .../viewmodels/AdoptionListViewModel.java | 24 ++++ .../viewmodels/AnalyticsViewModel.java | 73 ++++++++++++ .../AppointmentDetailViewModel.java | 4 +- .../viewmodels/AppointmentListViewModel.java | 24 ++++ .../viewmodels/AuthViewModel.java | 15 ++- .../viewmodels/ChatListViewModel.java | 54 +++++++++ .../viewmodels/CouponDetailViewModel.java | 18 +++ .../viewmodels/CouponListViewModel.java | 20 ++++ .../viewmodels/CustomerDetailViewModel.java | 9 ++ .../viewmodels/CustomerListViewModel.java | 26 +++++ .../viewmodels/InventoryDetailViewModel.java | 39 +++++++ .../viewmodels/InventoryListViewModel.java | 24 ++++ .../viewmodels/PetListViewModel.java | 37 ++++++ .../viewmodels/PetProfileViewModel.java | 9 ++ .../viewmodels/ProductDetailViewModel.java | 33 ++++++ .../viewmodels/ProductListViewModel.java | 21 ++++ .../ProductSupplierDetailViewModel.java | 43 +++++++ .../ProductSupplierListViewModel.java | 28 +++++ .../PurchaseOrderDetailViewModel.java | 3 + .../PurchaseOrderListViewModel.java | 21 ++++ .../viewmodels/RefundViewModel.java | 39 +++++++ .../viewmodels/SaleDetailViewModel.java | 106 ++++++++++++++++++ .../viewmodels/SaleListViewModel.java | 34 ++++++ .../viewmodels/ServiceDetailViewModel.java | 24 ++++ .../viewmodels/ServiceListViewModel.java | 17 +++ .../viewmodels/StaffDetailViewModel.java | 27 +++++ .../viewmodels/StaffListViewModel.java | 33 ++++++ .../viewmodels/SupplierDetailViewModel.java | 24 ++++ .../viewmodels/SupplierListViewModel.java | 17 +++ .../websocket/StompChatManager.java | 80 ++++++++++--- 160 files changed, 3098 insertions(+), 81 deletions(-) diff --git a/android/app/src/main/java/com/example/petstoremobile/activities/ForgotPasswordActivity.java b/android/app/src/main/java/com/example/petstoremobile/activities/ForgotPasswordActivity.java index 82ea9934..ef08f5ee 100644 --- a/android/app/src/main/java/com/example/petstoremobile/activities/ForgotPasswordActivity.java +++ b/android/app/src/main/java/com/example/petstoremobile/activities/ForgotPasswordActivity.java @@ -32,6 +32,9 @@ public class ForgotPasswordActivity extends AppCompatActivity { private ActivityForgotPasswordBinding binding; + /** + * Set the content view for forget password page + */ @Override protected void onCreate(Bundle savedInstanceState) { EdgeToEdge.enable(this); @@ -54,6 +57,10 @@ public class ForgotPasswordActivity extends AppCompatActivity { binding.btnBackToLogin.setOnClickListener(v -> finish()); } + /** + * A function to send a reset link to the given email address. + * Calls the forgotPassword endpoint. To send the reset link + * */ private void sendResetLink(String email) { binding.btnSubmit.setEnabled(false); diff --git a/android/app/src/main/java/com/example/petstoremobile/activities/HomeActivity.java b/android/app/src/main/java/com/example/petstoremobile/activities/HomeActivity.java index 01b4ca24..9e5fd6d0 100644 --- a/android/app/src/main/java/com/example/petstoremobile/activities/HomeActivity.java +++ b/android/app/src/main/java/com/example/petstoremobile/activities/HomeActivity.java @@ -78,7 +78,7 @@ public class HomeActivity extends AppCompatActivity { @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); - setIntent(intent); // Set the new intent so fragments can access updated extras + setIntent(intent); handleIntent(intent); } @@ -103,7 +103,7 @@ public class HomeActivity extends AppCompatActivity { } /** - * Requests POST_NOTIFICATIONS permission from the user if running on Android 13 and above. + * Requests for notification permission from the user if running on Android 13 and above. */ private void requestNotificationPermission() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { diff --git a/android/app/src/main/java/com/example/petstoremobile/activities/MainActivity.java b/android/app/src/main/java/com/example/petstoremobile/activities/MainActivity.java index 11925052..b7aa1f1b 100644 --- a/android/app/src/main/java/com/example/petstoremobile/activities/MainActivity.java +++ b/android/app/src/main/java/com/example/petstoremobile/activities/MainActivity.java @@ -98,7 +98,7 @@ public class MainActivity extends AppCompatActivity { } /** - * Executes the login process using the AuthViewModel and handles the authentication response. + * Perform login process using the AuthViewModel and handles the authentication response. */ private void performLogin(String username, String password) { viewModel.login(username, password).observe(this, resource -> { @@ -112,6 +112,7 @@ public class MainActivity extends AppCompatActivity { case SUCCESS: if (resource.data != null) { String role = resource.data.getRole(); + //Check if role is staff/admin or customer if ("CUSTOMER".equalsIgnoreCase(role)) { UIUtils.setViewsEnabled(true, binding.btnLogin); binding.tvLoginStatus.setText("Customers are not allowed to log in"); @@ -132,7 +133,7 @@ public class MainActivity extends AppCompatActivity { } /** - * Retrieves the logged-in user's profile information to save their ID before navigating to the home screen. + * Retrieves the user's profile information to save their ID before navigating to the home screen. */ private void fetchUserIdAndNavigate() { viewModel.getMe().observe(this, resource -> { diff --git a/android/app/src/main/java/com/example/petstoremobile/adapters/ActivityLogAdapter.java b/android/app/src/main/java/com/example/petstoremobile/adapters/ActivityLogAdapter.java index eb571ca2..ecd34994 100644 --- a/android/app/src/main/java/com/example/petstoremobile/adapters/ActivityLogAdapter.java +++ b/android/app/src/main/java/com/example/petstoremobile/adapters/ActivityLogAdapter.java @@ -25,10 +25,16 @@ public class ActivityLogAdapter extends RecyclerView.Adapter items; + /** + * Constructor for the ActivityLogAdapter. + */ public ActivityLogAdapter(List items) { this.items = items; } + /** + * Inflates the layout for an activity log item and creates a new ViewHolder. + */ @NonNull @Override public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { @@ -37,6 +43,9 @@ public class ActivityLogAdapter extends RecyclerView.Adapter adoptionList, OnAdoptionClickListener listener) { this.adoptionList = adoptionList; this.listener = listener; @@ -39,11 +42,17 @@ public class AdoptionAdapter extends RecyclerView.Adapter getSelectedKeys() { return selectionHelper.getSelectedKeys(); } + /** + * Resets the selection state, deselecting all items. + */ @Override public void clearSelection() { selectionHelper.clearSelection(); @@ -58,6 +67,9 @@ public class AdoptionAdapter extends RecyclerView.Adapter appointmentList, OnAppointmentClickListener appointmentClickListener) { this.appointmentList = appointmentList; @@ -40,25 +43,40 @@ public class AppointmentAdapter extends RecyclerView.Adapter getSelectedKeys() { return selectionHelper.getSelectedKeys(); } + /** + * Resets the selection state, deselecting all items. + */ @Override public void clearSelection() { selectionHelper.clearSelection(); } + /** + * ViewHolder class that holds references to the UI components for an appointment item. + */ public static class AppointmentViewHolder extends RecyclerView.ViewHolder { private final ItemAppointmentBinding binding; + /** + * Initializes the ViewHolder by finding the views within the item layout. + */ public AppointmentViewHolder(@NonNull ItemAppointmentBinding binding) { super(binding.getRoot()); this.binding = binding; } } + /** + * Inflates the layout for an appointment item and creates the ViewHolder. + */ @NonNull @Override public AppointmentViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { @@ -66,6 +84,9 @@ public class AppointmentAdapter extends RecyclerView.Adapter extends ArrayAdapter { public BlackTextArrayAdapter(@NonNull Context context, int resource, @NonNull T[] objects) { super(context, resource, objects); diff --git a/android/app/src/main/java/com/example/petstoremobile/adapters/ChatAdapter.java b/android/app/src/main/java/com/example/petstoremobile/adapters/ChatAdapter.java index 972ac56d..329adfe8 100644 --- a/android/app/src/main/java/com/example/petstoremobile/adapters/ChatAdapter.java +++ b/android/app/src/main/java/com/example/petstoremobile/adapters/ChatAdapter.java @@ -20,11 +20,17 @@ public class ChatAdapter extends RecyclerView.Adapter chatList, OnChatClickListener listener) { this.chatList = chatList; this.listener = listener; } + /** + * Inflates the layout for a chat item and creates the ViewHolder. + */ @NonNull @Override public ChatViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { @@ -32,6 +38,9 @@ public class ChatAdapter extends RecyclerView.Adapter listener.onChatClick(chat)); } + /** + * Returns the total number of chat items in the list. + */ @Override public int getItemCount() { return chatList.size(); } + /** + * ViewHolder class that holds references to the UI components for a chat item. + */ public static class ChatViewHolder extends RecyclerView.ViewHolder { final ItemChatBinding binding; + /** + * Initializes the ViewHolder with the chat item's view binding. + */ public ChatViewHolder(@NonNull ItemChatBinding binding) { super(binding.getRoot()); this.binding = binding; diff --git a/android/app/src/main/java/com/example/petstoremobile/adapters/CouponAdapter.java b/android/app/src/main/java/com/example/petstoremobile/adapters/CouponAdapter.java index ff9bbe65..10994ddd 100644 --- a/android/app/src/main/java/com/example/petstoremobile/adapters/CouponAdapter.java +++ b/android/app/src/main/java/com/example/petstoremobile/adapters/CouponAdapter.java @@ -30,11 +30,17 @@ public class CouponAdapter extends RecyclerView.Adapter coupons, OnCouponClickListener listener) { this.coupons = coupons; this.listener = listener; } + /** + * Inflates the layout for a coupon item and creates the ViewHolder. + */ @NonNull @Override public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { @@ -42,6 +48,9 @@ public class CouponAdapter extends RecyclerView.Adapter toggleSelection(coupon.getCouponId())); } + /** + * Toggles the selection state of a specific coupon by its ID. + */ private void toggleSelection(Long id) { if (selectedIds.contains(id)) { selectedIds.remove(id); @@ -105,6 +117,9 @@ public class CouponAdapter extends RecyclerView.Adapter getSelectedIds() { return selectedIds; } + /** + * Returns the total number of coupons in the list. + */ @Override public int getItemCount() { return coupons.size(); @@ -125,6 +146,9 @@ public class CouponAdapter extends RecyclerView.Adapter list, OnCustomerClickListener listener) { this.list = list; this.listener = listener; } + /** + * Sets the base URL for fetching customer profile images. + */ public void setBaseUrl(String baseUrl) { this.baseUrl = baseUrl; } + + /** + * Sets the authentication token for fetching images. + */ public void setToken(String token) { this.token = token; } + /** + * ViewHolder class for customer items. + */ public static class CustomerViewHolder extends RecyclerView.ViewHolder { final ItemCustomerBinding binding; + /** + * Initializes the ViewHolder with view binding. + */ public CustomerViewHolder(@NonNull ItemCustomerBinding binding) { super(binding.getRoot()); this.binding = binding; } } + /** + * Inflates the layout for a customer item and creates the ViewHolder. + */ @NonNull @Override public CustomerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { @@ -49,6 +68,9 @@ public class CustomerAdapter extends RecyclerView.Adapter listener.onCustomerClick(position)); } + /** + * Returns the total number of customers in the list. + */ @Override public int getItemCount() { return list.size(); } } diff --git a/android/app/src/main/java/com/example/petstoremobile/adapters/EmployeeAdapter.java b/android/app/src/main/java/com/example/petstoremobile/adapters/EmployeeAdapter.java index 8213dbd0..af8f99e5 100644 --- a/android/app/src/main/java/com/example/petstoremobile/adapters/EmployeeAdapter.java +++ b/android/app/src/main/java/com/example/petstoremobile/adapters/EmployeeAdapter.java @@ -25,28 +25,46 @@ public class EmployeeAdapter extends RecyclerView.Adapter list, OnEmployeeClickListener listener) { this.list = list; this.listener = listener; } + /** + * Sets the base URL for fetching employee profile images. + */ public void setBaseUrl(String baseUrl) { this.baseUrl = baseUrl; } + /** + * Sets the authentication token for fetching images. + */ public void setToken(String token) { this.token = token; } + /** + * ViewHolder class for employee items. + */ public static class EmployeeViewHolder extends RecyclerView.ViewHolder { private final ItemEmployeeBinding binding; + /** + * Initializes the ViewHolder with view binding. + */ public EmployeeViewHolder(@NonNull ItemEmployeeBinding binding) { super(binding.getRoot()); this.binding = binding; } } + /** + * Inflates the layout for an employee item and creates the ViewHolder. + */ @NonNull @Override public EmployeeViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { @@ -55,6 +73,9 @@ public class EmployeeAdapter extends RecyclerView.Adapter listener.onEmployeeClick(position)); } + /** + * Returns the total number of employees in the list. + */ @Override public int getItemCount() { return list.size(); } } diff --git a/android/app/src/main/java/com/example/petstoremobile/adapters/InventoryAdapter.java b/android/app/src/main/java/com/example/petstoremobile/adapters/InventoryAdapter.java index 9fbc1481..a015bb97 100644 --- a/android/app/src/main/java/com/example/petstoremobile/adapters/InventoryAdapter.java +++ b/android/app/src/main/java/com/example/petstoremobile/adapters/InventoryAdapter.java @@ -27,6 +27,9 @@ public class InventoryAdapter extends RecyclerView.Adapter inventoryList, OnInventoryClickListener clickListener) { this.inventoryList = inventoryList; this.clickListener = clickListener; @@ -43,25 +46,40 @@ public class InventoryAdapter extends RecyclerView.Adapter getSelectedKeys() { return selectionHelper.getSelectedKeys(); } + /** + * Resets the selection state, deselecting all items. + */ @Override public void clearSelection() { selectionHelper.clearSelection(); } + /** + * ViewHolder class that holds references to the UI components for an inventory item. + */ public static class InventoryViewHolder extends RecyclerView.ViewHolder { final ItemInventoryBinding binding; + /** + * Initializes the ViewHolder with view binding. + */ public InventoryViewHolder(@NonNull ItemInventoryBinding binding) { super(binding.getRoot()); this.binding = binding; } } + /** + * Inflates the layout for an inventory item and creates the ViewHolder. + */ @NonNull @Override public InventoryViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { @@ -69,6 +87,9 @@ public class InventoryAdapter extends RecyclerView.Adapter messages, Long currentUserId) { this.messages = messages; this.currentUserId = currentUserId; setHasStableIds(true); } + /** + * Returns an ID for each message. + */ @Override public long getItemId(int position) { Message m = messages.get(position); return m.getId() != null ? m.getId() : position; } + /** + * Updates the current user's ID and refreshes the list. + */ public void setCurrentUserId(Long id) { this.currentUserId = id; notifyDataSetChanged(); } + /** + * Updates the staff ID to identify staff messages in the UI. + */ public void setStaffId(Long id) { this.staffId = id; notifyDataSetChanged(); } + /** + * Sets the authentication token. + */ public void setToken(String token) { this.token = token; } + /** + * Sets the base API URL. + */ public void setBaseUrl(String baseUrl) { this.baseUrl = baseUrl; } + /** + * Sets a listener for clicks on message attachments. + */ public void setOnAttachmentClickListener(OnAttachmentClickListener listener) { this.attachmentClickListener = listener; } + /** + * Determines if a message is 'sent' or 'received' based on the sender's ID. + */ @Override public int getItemViewType(int position) { Message m = messages.get(position); @@ -80,6 +104,9 @@ public class MessageAdapter extends RecyclerView.Adapter i void onSelectionChanged(int selectedCount); } - //Constructor + /** + * Constructor for PetAdapter. + */ public PetAdapter(List petList, OnPetClickListener petClickListener) { this.petList = petList; this.petClickListener = petClickListener; @@ -48,35 +50,54 @@ public class PetAdapter extends RecyclerView.Adapter i }); } + /** + * Sets the base URL for fetching pet images from the server. + */ public void setBaseUrl(String baseUrl) { this.baseUrl = baseUrl; } + /** + * Sets the authentication token + */ public void setToken(String token) { this.token = token; } + /** + * Returns a list of IDs for the currently selected pet items. + */ @Override public List getSelectedKeys() { return selectionHelper.getSelectedKeys(); } + /** + * Resets the selection state, deselecting all items. + */ @Override public void clearSelection() { selectionHelper.clearSelection(); } - // Get the controls of each row in recycler view + /** + * ViewHolder class that holds references to the UI components for a pet item. + */ public static class PetViewHolder extends RecyclerView.ViewHolder { private final ItemPetBinding binding; + /** + * Initializes the ViewHolder with view binding. + */ public PetViewHolder(@NonNull ItemPetBinding binding) { super(binding.getRoot()); this.binding = binding; } } - // Create a new row view + /** + * Inflates the layout for a pet item and creates the ViewHolder. + */ @NonNull @Override public PetViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { @@ -84,7 +105,9 @@ public class PetAdapter extends RecyclerView.Adapter i return new PetViewHolder(binding); } - //populate the row with pet data + /** + * Binds pet data to the UI components. + */ @Override public void onBindViewHolder(@NonNull PetViewHolder holder, int position) { PetDTO pet = petList.get(position); @@ -103,7 +126,7 @@ public class PetAdapter extends RecyclerView.Adapter i binding.tvPetStatus.setText(pet.getPetStatus()); - //Set the status color depending on availability. If available, green, If Pending, yellow, otherwise red + //Set the status color depending on availability if (pet.getPetStatus() != null) { switch (pet.getPetStatus()) { case "Available": @@ -157,6 +180,9 @@ public class PetAdapter extends RecyclerView.Adapter i }); } + /** + * Returns the total number of pet items in the list. + */ @Override public int getItemCount() { return petList.size(); diff --git a/android/app/src/main/java/com/example/petstoremobile/adapters/ProductAdapter.java b/android/app/src/main/java/com/example/petstoremobile/adapters/ProductAdapter.java index f5f897cc..9adea207 100644 --- a/android/app/src/main/java/com/example/petstoremobile/adapters/ProductAdapter.java +++ b/android/app/src/main/java/com/example/petstoremobile/adapters/ProductAdapter.java @@ -22,28 +22,46 @@ public class ProductAdapter extends RecyclerView.Adapter productList, OnProductClickListener listener) { this.productList = productList; this.listener = listener; } + /** + * Sets the base URL for fetching product images. + */ public void setBaseUrl(String baseUrl) { this.baseUrl = baseUrl; } + /** + * Sets the authentication token + */ public void setToken(String token) { this.token = token; } + /** + * ViewHolder class for product items. + */ public static class ProductViewHolder extends RecyclerView.ViewHolder { final ItemProductBinding binding; + /** + * Initializes the ViewHolder with view binding. + */ public ProductViewHolder(@NonNull ItemProductBinding binding) { super(binding.getRoot()); this.binding = binding; } } + /** + * Inflates the layout for a product item and creates the ViewHolder. + */ @NonNull @Override public ProductViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { @@ -51,6 +69,9 @@ public class ProductAdapter extends RecyclerView.Adapter listener.onProductClick(position)); } + /** + * Returns the total number of product items in the list. + */ @Override public int getItemCount() { return productList.size(); } } \ No newline at end of file diff --git a/android/app/src/main/java/com/example/petstoremobile/adapters/ProductSupplierAdapter.java b/android/app/src/main/java/com/example/petstoremobile/adapters/ProductSupplierAdapter.java index 231af741..c5c07e00 100644 --- a/android/app/src/main/java/com/example/petstoremobile/adapters/ProductSupplierAdapter.java +++ b/android/app/src/main/java/com/example/petstoremobile/adapters/ProductSupplierAdapter.java @@ -25,6 +25,9 @@ public class ProductSupplierAdapter extends RecyclerView.Adapter list, OnProductSupplierClickListener listener) { this.list = list; this.listener = listener; @@ -41,25 +44,40 @@ public class ProductSupplierAdapter extends RecyclerView.Adapter getSelectedKeys() { return selectionHelper.getSelectedKeys(); } + /** + * Clears all selected items and exits selection mode. + */ @Override public void clearSelection() { selectionHelper.clearSelection(); } + /** + * ViewHolder for Product-Supplier relationship items. + */ public static class PSViewHolder extends RecyclerView.ViewHolder { final ItemProductSupplierBinding binding; + /** + * Initializes the ViewHolder with view binding. + */ public PSViewHolder(@NonNull ItemProductSupplierBinding binding) { super(binding.getRoot()); this.binding = binding; } } + /** + * Inflates the layout for a Product-Supplier item. + */ @NonNull @Override public PSViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { @@ -67,6 +85,9 @@ public class ProductSupplierAdapter extends RecyclerView.Adapter list, OnPurchaseOrderClickListener listener) { this.list = list; this.listener = listener; } + /** + * ViewHolder for Purchase Order items. + */ public static class POViewHolder extends RecyclerView.ViewHolder { final ItemPurchaseOrderBinding binding; + /** + * Initializes the ViewHolder with view binding. + */ public POViewHolder(@NonNull ItemPurchaseOrderBinding binding) { super(binding.getRoot()); this.binding = binding; } } + /** + * Inflates the layout for a Purchase Order item. + */ @NonNull @Override public POViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { @@ -38,6 +50,9 @@ public class PurchaseOrderAdapter extends RecyclerView.Adapter saleList, OnSaleClickListener listener) { this.saleList = saleList; this.listener = listener; } + /** + * ViewHolder for Sale record items. + */ public static class SaleViewHolder extends RecyclerView.ViewHolder { final ItemSaleBinding binding; + /** + * Initializes the ViewHolder with view binding. + */ public SaleViewHolder(@NonNull ItemSaleBinding binding) { super(binding.getRoot()); this.binding = binding; } } + /** + * Inflates the layout for a Sale record item. + */ @NonNull @Override public SaleViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { @@ -41,6 +53,9 @@ public class SaleAdapter extends RecyclerView.Adapter serviceList, OnServiceClickListener clickListener) { this.serviceList = serviceList; this.clickListener = clickListener; @@ -47,29 +50,40 @@ public class ServiceAdapter extends RecyclerView.Adapter getSelectedKeys() { return selectionHelper.getSelectedKeys(); } + /** + * Clears all selected items and exits selection mode. + */ @Override public void clearSelection() { selectionHelper.clearSelection(); } /** - * ViewHolder class for service items. + * ViewHolder for Service items. */ public static class ServiceViewHolder extends RecyclerView.ViewHolder { final ItemServiceBinding binding; + /** + * Initializes the ViewHolder with view binding. + */ public ServiceViewHolder(@NonNull ItemServiceBinding binding) { super(binding.getRoot()); this.binding = binding; } } - // Create a new row view + /** + * Inflates the layout for a Service item. + */ @NonNull @Override public ServiceViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { @@ -77,7 +91,9 @@ public class ServiceAdapter extends RecyclerView.Adapter supplierList, OnSupplierClickListener supplierClickListener) { this.supplierList = supplierList; this.supplierClickListener = supplierClickListener; @@ -43,27 +45,40 @@ public class SupplierAdapter extends RecyclerView.Adapter getSelectedKeys() { return selectionHelper.getSelectedKeys(); } + /** + * Clears all selected items and exits selection mode. + */ @Override public void clearSelection() { selectionHelper.clearSelection(); } - // Get the controls of each row in recycler view + /** + * ViewHolder for Supplier items. + */ public static class SupplierViewHolder extends RecyclerView.ViewHolder { final ItemSupplierBinding binding; + /** + * Initializes the ViewHolder with view binding. + */ public SupplierViewHolder(@NonNull ItemSupplierBinding binding) { super(binding.getRoot()); this.binding = binding; } } - // Create a new row view + /** + * Inflates the layout for a Supplier item. + */ @NonNull @Override public SupplierViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { @@ -71,7 +86,9 @@ public class SupplierAdapter extends RecyclerView.Adapter extends ArrayAdapter { public WhiteTextArrayAdapter(@NonNull Context context, int resource, @NonNull T[] objects) { super(context, resource, objects); diff --git a/android/app/src/main/java/com/example/petstoremobile/api/ActivityLogApi.java b/android/app/src/main/java/com/example/petstoremobile/api/ActivityLogApi.java index 12ceb5bd..4ff8af6d 100644 --- a/android/app/src/main/java/com/example/petstoremobile/api/ActivityLogApi.java +++ b/android/app/src/main/java/com/example/petstoremobile/api/ActivityLogApi.java @@ -8,8 +8,10 @@ import retrofit2.Call; import retrofit2.http.GET; import retrofit2.http.Query; +// api calls to get activity logs public interface ActivityLogApi { + // Get activity logs with filters @GET("api/v1/activity-logs") Call> getActivityLogs( @Query("limit") int limit, diff --git a/android/app/src/main/java/com/example/petstoremobile/api/AdoptionApi.java b/android/app/src/main/java/com/example/petstoremobile/api/AdoptionApi.java index 6e1de73d..fa9114b5 100644 --- a/android/app/src/main/java/com/example/petstoremobile/api/AdoptionApi.java +++ b/android/app/src/main/java/com/example/petstoremobile/api/AdoptionApi.java @@ -14,8 +14,10 @@ import retrofit2.http.PUT; import retrofit2.http.Path; import retrofit2.http.Query; +// api calls for adoptions public interface AdoptionApi { + // Get all adoptions with filters @GET("api/v1/adoptions") Call> getAllAdoptions( @Query("page") int page, @@ -27,18 +29,23 @@ public interface AdoptionApi { @Query("employeeId") Long employeeId, @Query("sort") String sort); + // Get adoption by id @GET("api/v1/adoptions/{id}") Call getAdoptionById(@Path("id") Long id); + // Create adoption @POST("api/v1/adoptions") Call createAdoption(@Body AdoptionDTO adoption); + // Update adoption @PUT("api/v1/adoptions/{id}") Call updateAdoption(@Path("id") Long id, @Body AdoptionDTO adoption); + // Delete adoption @DELETE("api/v1/adoptions/{id}") Call deleteAdoption(@Path("id") Long id); + // Bulk delete adoptions @HTTP(method = "DELETE", path = "api/v1/adoptions", hasBody = true) Call bulkDeleteAdoptions(@Body BulkDeleteRequest request); } diff --git a/android/app/src/main/java/com/example/petstoremobile/api/AppointmentApi.java b/android/app/src/main/java/com/example/petstoremobile/api/AppointmentApi.java index 5bc88643..f0752c00 100644 --- a/android/app/src/main/java/com/example/petstoremobile/api/AppointmentApi.java +++ b/android/app/src/main/java/com/example/petstoremobile/api/AppointmentApi.java @@ -14,8 +14,10 @@ import retrofit2.http.PUT; import retrofit2.http.Path; import retrofit2.http.Query; +// api calls for appointments public interface AppointmentApi { + // Get all appointments with filters @GET("api/v1/appointments") Call> getAllAppointments( @Query("page") int page, @@ -27,18 +29,23 @@ public interface AppointmentApi { @Query("employeeId") Long employeeId, @Query("sort") String sort); + // Get appointment by id @GET("api/v1/appointments/{id}") Call getAppointmentById(@Path("id") Long id); + // Create appointment @POST("api/v1/appointments") Call createAppointment(@Body AppointmentDTO appointment); + // Update appointment @PUT("api/v1/appointments/{id}") Call updateAppointment(@Path("id") Long id, @Body AppointmentDTO appointment); + // Delete appointment @DELETE("api/v1/appointments/{id}") Call deleteAppointment(@Path("id") Long id); + // Bulk delete appointments @HTTP(method = "DELETE", path = "api/v1/appointments", hasBody = true) Call bulkDeleteAppointments(@Body BulkDeleteRequest request); -} \ No newline at end of file +} diff --git a/android/app/src/main/java/com/example/petstoremobile/api/CategoryApi.java b/android/app/src/main/java/com/example/petstoremobile/api/CategoryApi.java index d1084482..a82e0ab8 100644 --- a/android/app/src/main/java/com/example/petstoremobile/api/CategoryApi.java +++ b/android/app/src/main/java/com/example/petstoremobile/api/CategoryApi.java @@ -6,8 +6,10 @@ import retrofit2.Call; import retrofit2.http.GET; import retrofit2.http.Query; +// api calls for categories public interface CategoryApi { + // Get all categories with pagination @GET("api/v1/categories") Call> getAllCategories( @Query("page") int page, diff --git a/android/app/src/main/java/com/example/petstoremobile/api/ChatApi.java b/android/app/src/main/java/com/example/petstoremobile/api/ChatApi.java index 7a4ab393..8a818a0a 100644 --- a/android/app/src/main/java/com/example/petstoremobile/api/ChatApi.java +++ b/android/app/src/main/java/com/example/petstoremobile/api/ChatApi.java @@ -12,15 +12,18 @@ import retrofit2.http.GET; import retrofit2.http.PUT; import retrofit2.http.Path; -//api calls to get conversations +// api calls for chat conversations public interface ChatApi { + // Get all conversations @GET("api/v1/chat/conversations") Call> getAllConversations(); + // Get conversation by id @GET("api/v1/chat/conversations/{conversationId}") Call getConversationById(@Path("conversationId") Long conversationId); + // Update conversation status @PUT("api/v1/chat/conversations/{conversationId}") Call updateConversationStatus(@Path("conversationId") Long conversationId, @Body UpdateConversationStatusRequest request); diff --git a/android/app/src/main/java/com/example/petstoremobile/api/CustomerApi.java b/android/app/src/main/java/com/example/petstoremobile/api/CustomerApi.java index 55c51682..14be64e0 100644 --- a/android/app/src/main/java/com/example/petstoremobile/api/CustomerApi.java +++ b/android/app/src/main/java/com/example/petstoremobile/api/CustomerApi.java @@ -15,23 +15,30 @@ import retrofit2.http.PUT; import retrofit2.http.Path; import retrofit2.http.Query; +// api calls for customers public interface CustomerApi { + // Get all customers with pagination @GET("api/v1/customers") Call> getAllCustomers(@Query("page") int page, @Query("size") int size); + // Get customer by id @GET("api/v1/customers/{customerId}") Call getCustomerById(@Path("customerId") Long customerId); + // Update customer @PUT("api/v1/customers/{customerId}") Call updateCustomer(@Path("customerId") Long customerId, @Body CustomerDTO customer); + // Delete customer @DELETE("api/v1/customers/{customerId}") Call deleteCustomer(@Path("customerId") Long customerId); + // Register customer @POST("api/v1/auth/register") Call registerCustomer(@Body CustomerDTO customer); + // Get customer dropdowns @GET("api/v1/dropdowns/customers") Call> getCustomerDropdowns(); } diff --git a/android/app/src/main/java/com/example/petstoremobile/api/EmployeeApi.java b/android/app/src/main/java/com/example/petstoremobile/api/EmployeeApi.java index bbd873c3..33f08264 100644 --- a/android/app/src/main/java/com/example/petstoremobile/api/EmployeeApi.java +++ b/android/app/src/main/java/com/example/petstoremobile/api/EmployeeApi.java @@ -5,28 +5,28 @@ import com.example.petstoremobile.dtos.PageResponse; import retrofit2.Call; import retrofit2.http.*; +// api calls for employees public interface EmployeeApi { + // Get all employees with pagination @GET("api/v1/employees") Call> getAllEmployees( @Query("page") int page, @Query("size") int size); + // Get employee by id @GET("api/v1/employees/{id}") Call getEmployeeById(@Path("id") Long id); + // Create employee @POST("api/v1/employees") Call createEmployee(@Body EmployeeDTO employee); + // Update employee @PUT("api/v1/employees/{id}") Call updateEmployee(@Path("id") Long id, @Body EmployeeDTO employee); + // Delete employee @DELETE("api/v1/employees/{id}") Call deleteEmployee(@Path("id") Long id); } - - - - - - diff --git a/android/app/src/main/java/com/example/petstoremobile/api/InventoryApi.java b/android/app/src/main/java/com/example/petstoremobile/api/InventoryApi.java index fa1e17b4..e9b3bb7c 100644 --- a/android/app/src/main/java/com/example/petstoremobile/api/InventoryApi.java +++ b/android/app/src/main/java/com/example/petstoremobile/api/InventoryApi.java @@ -14,8 +14,10 @@ import retrofit2.http.PUT; import retrofit2.http.Path; import retrofit2.http.Query; +// api calls for inventory public interface InventoryApi { + // Get all inventory with filters @GET("api/v1/inventory") Call> getAllInventory( @Query("page") int page, @@ -24,23 +26,23 @@ public interface InventoryApi { @Query("storeId") Long storeId, @Query("sort") String sort); - // GET /api/v1/inventory/{id} + // Get inventory by id @GET("api/v1/inventory/{id}") Call getInventoryById(@Path("id") Long id); - // POST /api/v1/inventory + // Create inventory @POST("api/v1/inventory") Call createInventory(@Body InventoryDTO request); - // PUT /api/v1/inventory/{id} + // Update inventory @PUT("api/v1/inventory/{id}") Call updateInventory(@Path("id") Long id, @Body InventoryDTO request); - // DELETE /api/v1/inventory/{id} + // Delete inventory @DELETE("api/v1/inventory/{id}") Call deleteInventory(@Path("id") Long id); - // DELETE /api/v1/inventory (bulk delete) + // Bulk delete inventory @HTTP(method = "DELETE", path = "api/v1/inventory", hasBody = true) Call bulkDeleteInventory(@Body BulkDeleteRequest request); } diff --git a/android/app/src/main/java/com/example/petstoremobile/api/MessageApi.java b/android/app/src/main/java/com/example/petstoremobile/api/MessageApi.java index e5504a03..cb921932 100644 --- a/android/app/src/main/java/com/example/petstoremobile/api/MessageApi.java +++ b/android/app/src/main/java/com/example/petstoremobile/api/MessageApi.java @@ -15,15 +15,18 @@ import retrofit2.http.Part; import retrofit2.http.Path; import retrofit2.http.Streaming; -//api calls to get and send messages +// api calls for messages public interface MessageApi { + // Get messages for a conversation @GET("api/v1/chat/conversations/{id}/messages") Call> getMessages(@Path("id") Long conversationId); + // Send a message @POST("api/v1/chat/conversations/{id}/messages") Call sendMessage(@Path("id") Long conversationId, @Body SendMessageRequest request); + // Send a message with attachment @Multipart @POST("api/v1/chat/conversations/{id}/attachments") Call sendMessageWithAttachment( @@ -32,6 +35,7 @@ public interface MessageApi { @Part MultipartBody.Part file ); + // Download attachment @GET("api/v1/chat/messages/{id}/attachment") @Streaming Call downloadAttachment(@Path("id") Long messageId); diff --git a/android/app/src/main/java/com/example/petstoremobile/api/PetApi.java b/android/app/src/main/java/com/example/petstoremobile/api/PetApi.java index b554166b..06e522f0 100644 --- a/android/app/src/main/java/com/example/petstoremobile/api/PetApi.java +++ b/android/app/src/main/java/com/example/petstoremobile/api/PetApi.java @@ -20,7 +20,7 @@ import retrofit2.http.Part; import retrofit2.http.Path; import retrofit2.http.Query; -//api calls to CRUD pets +// api calls to CRUD pets public interface PetApi { // endpoint for downloading the pet's image file String PET_IMAGE_PATH = "api/v1/pets/%d/image"; @@ -38,18 +38,23 @@ public interface PetApi { @Query("sort") String sort ); + // Get pets by customer id @GET("api/v1/dropdowns/customers/{customerId}/pets") Call> getCustomerPets(@Path("customerId") Long customerId); + // Get adoption pets @GET("api/v1/dropdowns/adoption-pets") Call> getAdoptionPets(@Query("storeId") Long storeId); + // Get pet dropdowns @GET("api/v1/dropdowns/pets") Call> getPetDropdowns(); + // Get pet species dropdowns @GET("api/v1/dropdowns/pet-species") Call> getPetSpeciesDropdowns(); + // Get pet breeds dropdowns @GET("api/v1/dropdowns/pet-breeds") Call> getPetBreedsDropdowns(@Query("species") String species); @@ -81,5 +86,4 @@ public interface PetApi { // Delete pet image @DELETE("api/v1/pets/{id}/image") Call deletePetImage(@Path("id") Long id); - } diff --git a/android/app/src/main/java/com/example/petstoremobile/api/ProductApi.java b/android/app/src/main/java/com/example/petstoremobile/api/ProductApi.java index 8aeb596e..88d7df0f 100644 --- a/android/app/src/main/java/com/example/petstoremobile/api/ProductApi.java +++ b/android/app/src/main/java/com/example/petstoremobile/api/ProductApi.java @@ -9,9 +9,12 @@ import retrofit2.http.*; import java.util.List; +// api calls for products public interface ProductApi { + // endpoint for downloading the product's image file String PRODUCT_IMAGE_PATH = "api/v1/products/%d/image"; + // Get all products with filters @GET("api/v1/products") Call> getAllProducts( @Query("q") String query, @@ -20,28 +23,36 @@ public interface ProductApi { @Query("size") int size, @Query("sort") String sort); + // Get product by id @GET("api/v1/products/{id}") Call getProductById(@Path("id") Long id); + // Create product @POST("api/v1/products") Call createProduct(@Body ProductDTO product); + // Update product @PUT("api/v1/products/{id}") Call updateProduct(@Path("id") Long id, @Body ProductDTO product); + // Delete product @DELETE("api/v1/products/{id}") Call deleteProduct(@Path("id") Long id); + // Upload product image @Multipart @POST("api/v1/products/{id}/image") Call uploadProductImage(@Path("id") Long id, @Part MultipartBody.Part image); + // Delete product image @DELETE("api/v1/products/{id}/image") Call deleteProductImage(@Path("id") Long id); + // Get product dropdowns @GET("api/v1/dropdowns/products") Call> getProductDropdowns(); + // Get category dropdowns @GET("api/v1/dropdowns/categories") Call> getCategoryDropdowns(); -} \ No newline at end of file +} diff --git a/android/app/src/main/java/com/example/petstoremobile/api/ProductSupplierApi.java b/android/app/src/main/java/com/example/petstoremobile/api/ProductSupplierApi.java index b4414be5..03f6d891 100644 --- a/android/app/src/main/java/com/example/petstoremobile/api/ProductSupplierApi.java +++ b/android/app/src/main/java/com/example/petstoremobile/api/ProductSupplierApi.java @@ -6,8 +6,10 @@ import com.example.petstoremobile.dtos.ProductSupplierDTO; import retrofit2.Call; import retrofit2.http.*; +// api calls for product-supplier relationships public interface ProductSupplierApi { + // Get all product-suppliers with filters @GET("api/v1/product-suppliers") Call> getAllProductSuppliers( @Query("page") int page, @@ -17,24 +19,30 @@ public interface ProductSupplierApi { @Query("supplierId") Long supplierId, @Query("sort") String sort); + // Get product-supplier by composite id @GET("api/v1/product-suppliers/{productId}/{supplierId}") Call getProductSupplierById( @Path("productId") Long productId, @Path("supplierId") Long supplierId); + // Create product-supplier @POST("api/v1/product-suppliers") Call createProductSupplier(@Body ProductSupplierDTO dto); + // Update product-supplier @PUT("api/v1/product-suppliers/{productId}/{supplierId}") Call updateProductSupplier( @Path("productId") Long productId, @Path("supplierId") Long supplierId, @Body ProductSupplierDTO dto); + // Delete product-supplier @DELETE("api/v1/product-suppliers/{productId}/{supplierId}") Call deleteProductSupplier( @Path("productId") Long productId, @Path("supplierId") Long supplierId); + + // Bulk delete product-suppliers @HTTP(method = "DELETE", path = "api/v1/product-suppliers", hasBody = true) Call bulkDeleteProductSuppliers(@Body BulkDeleteRequest request); -} \ No newline at end of file +} diff --git a/android/app/src/main/java/com/example/petstoremobile/api/PurchaseOrderApi.java b/android/app/src/main/java/com/example/petstoremobile/api/PurchaseOrderApi.java index ebb99139..8746ed08 100644 --- a/android/app/src/main/java/com/example/petstoremobile/api/PurchaseOrderApi.java +++ b/android/app/src/main/java/com/example/petstoremobile/api/PurchaseOrderApi.java @@ -7,8 +7,10 @@ import retrofit2.http.GET; import retrofit2.http.Path; import retrofit2.http.Query; +// api calls for purchase orders public interface PurchaseOrderApi { + // Get all purchase orders with filters @GET("api/v1/purchase-orders") Call> getAllPurchaseOrders( @Query("page") int page, @@ -17,6 +19,7 @@ public interface PurchaseOrderApi { @Query("storeId") Long storeId, @Query("sort") String sort); + // Get purchase order by id @GET("api/v1/purchase-orders/{id}") Call getPurchaseOrderById(@Path("id") Long id); } \ No newline at end of file diff --git a/android/app/src/main/java/com/example/petstoremobile/api/RefundApi.java b/android/app/src/main/java/com/example/petstoremobile/api/RefundApi.java index d7ba9575..6e3591bc 100644 --- a/android/app/src/main/java/com/example/petstoremobile/api/RefundApi.java +++ b/android/app/src/main/java/com/example/petstoremobile/api/RefundApi.java @@ -6,20 +6,26 @@ import retrofit2.http.*; import java.util.List; +// api calls for refunds public interface RefundApi { + // Get all refunds @GET("api/v1/refunds") Call> getAllRefunds(); + // Get refund by id @GET("api/v1/refunds/{id}") Call getRefundById(@Path("id") Long id); + // Create refund @POST("api/v1/refunds") Call createRefund(@Body RefundDTO refund); + // Update refund @PUT("api/v1/refunds/{id}") Call updateRefund(@Path("id") Long id, @Body RefundDTO refund); + // Delete refund @DELETE("api/v1/refunds/{id}") Call deleteRefund(@Path("id") Long id); } \ No newline at end of file diff --git a/android/app/src/main/java/com/example/petstoremobile/api/SaleApi.java b/android/app/src/main/java/com/example/petstoremobile/api/SaleApi.java index cec94044..6d333dd5 100644 --- a/android/app/src/main/java/com/example/petstoremobile/api/SaleApi.java +++ b/android/app/src/main/java/com/example/petstoremobile/api/SaleApi.java @@ -10,8 +10,10 @@ import retrofit2.http.POST; import retrofit2.http.Path; import retrofit2.http.Query; +// api calls for sales public interface SaleApi { + // Get all sales with filters @GET("api/v1/sales") Call> getAllSales( @Query("page") int page, @@ -23,9 +25,11 @@ public interface SaleApi { @Query("customerId") Long customerId, @Query("sort") String sort); + // Get sale by id @GET("api/v1/sales/{id}") Call getSaleById(@Path("id") Long id); + // Create sale @POST("api/v1/sales") Call createSale(@Body SaleDTO sale); } diff --git a/android/app/src/main/java/com/example/petstoremobile/api/ServiceApi.java b/android/app/src/main/java/com/example/petstoremobile/api/ServiceApi.java index 43014a53..9784524b 100644 --- a/android/app/src/main/java/com/example/petstoremobile/api/ServiceApi.java +++ b/android/app/src/main/java/com/example/petstoremobile/api/ServiceApi.java @@ -14,7 +14,7 @@ import retrofit2.http.PUT; import retrofit2.http.Path; import retrofit2.http.Query; -//api calls to CRUD services +// api calls to CRUD services public interface ServiceApi { // Get all services @GET("api/v1/services") diff --git a/android/app/src/main/java/com/example/petstoremobile/api/StoreApi.java b/android/app/src/main/java/com/example/petstoremobile/api/StoreApi.java index f71b92b6..3370dd03 100644 --- a/android/app/src/main/java/com/example/petstoremobile/api/StoreApi.java +++ b/android/app/src/main/java/com/example/petstoremobile/api/StoreApi.java @@ -11,16 +11,20 @@ import retrofit2.http.GET; import retrofit2.http.Path; import retrofit2.http.Query; +// api calls for stores public interface StoreApi { + // Get all stores with pagination @GET("api/v1/stores") Call> getAllStores( @Query("page") int page, @Query("size") int size); + // Get store dropdowns @GET("api/v1/dropdowns/stores") Call> getStoreDropdowns(); + // Get employees of a specific store @GET("api/v1/dropdowns/stores/{storeId}/employees") Call> getStoreEmployees(@Path("storeId") Long storeId); } diff --git a/android/app/src/main/java/com/example/petstoremobile/api/UserApi.java b/android/app/src/main/java/com/example/petstoremobile/api/UserApi.java index 8346e221..dbc5640b 100644 --- a/android/app/src/main/java/com/example/petstoremobile/api/UserApi.java +++ b/android/app/src/main/java/com/example/petstoremobile/api/UserApi.java @@ -7,9 +7,12 @@ import retrofit2.Call; import retrofit2.http.GET; import retrofit2.http.Query; +// api calls for users public interface UserApi { + // endpoint for downloading the user's avatar file String AVATAR_PATH = "api/v1/users/%d/avatar/file"; + // Get all users with filters @GET("api/v1/users") Call> getUsers(@Query("role") String role, @Query("page") int page, @Query("size") int size); } diff --git a/android/app/src/main/java/com/example/petstoremobile/api/auth/TokenManager.java b/android/app/src/main/java/com/example/petstoremobile/api/auth/TokenManager.java index dc6096de..f28395d3 100644 --- a/android/app/src/main/java/com/example/petstoremobile/api/auth/TokenManager.java +++ b/android/app/src/main/java/com/example/petstoremobile/api/auth/TokenManager.java @@ -8,6 +8,7 @@ import javax.inject.Singleton; import dagger.hilt.android.qualifiers.ApplicationContext; +//Used to save and retrieve login data @Singleton public class TokenManager { private static final String TOKEN_KEY = "token"; diff --git a/android/app/src/main/java/com/example/petstoremobile/dtos/ActivityLogDTO.java b/android/app/src/main/java/com/example/petstoremobile/dtos/ActivityLogDTO.java index 2d4d0f6d..4a210a5d 100644 --- a/android/app/src/main/java/com/example/petstoremobile/dtos/ActivityLogDTO.java +++ b/android/app/src/main/java/com/example/petstoremobile/dtos/ActivityLogDTO.java @@ -1,5 +1,8 @@ package com.example.petstoremobile.dtos; +/** + * Data Transfer Object for activity logs. + */ public class ActivityLogDTO { private Long logId; private String activity; diff --git a/android/app/src/main/java/com/example/petstoremobile/dtos/AdoptionDTO.java b/android/app/src/main/java/com/example/petstoremobile/dtos/AdoptionDTO.java index d48bc942..66459bee 100644 --- a/android/app/src/main/java/com/example/petstoremobile/dtos/AdoptionDTO.java +++ b/android/app/src/main/java/com/example/petstoremobile/dtos/AdoptionDTO.java @@ -2,6 +2,9 @@ package com.example.petstoremobile.dtos; import java.math.BigDecimal; +/** + * Data Transfer Object for pet adoptions. + */ public class AdoptionDTO { private Long adoptionId; diff --git a/android/app/src/main/java/com/example/petstoremobile/dtos/AppointmentDTO.java b/android/app/src/main/java/com/example/petstoremobile/dtos/AppointmentDTO.java index 37f6640f..c793a142 100644 --- a/android/app/src/main/java/com/example/petstoremobile/dtos/AppointmentDTO.java +++ b/android/app/src/main/java/com/example/petstoremobile/dtos/AppointmentDTO.java @@ -1,5 +1,8 @@ package com.example.petstoremobile.dtos; +/** + * Data Transfer Object for appointments. + */ public class AppointmentDTO { private Long appointmentId; diff --git a/android/app/src/main/java/com/example/petstoremobile/dtos/AuthDTO.java b/android/app/src/main/java/com/example/petstoremobile/dtos/AuthDTO.java index 6aecdbc3..563b1b5f 100644 --- a/android/app/src/main/java/com/example/petstoremobile/dtos/AuthDTO.java +++ b/android/app/src/main/java/com/example/petstoremobile/dtos/AuthDTO.java @@ -1,6 +1,8 @@ package com.example.petstoremobile.dtos; -//Used to send login data to the backend +/** + * Data Transfer Object for authentication credentials. + */ public class AuthDTO { public static class LoginRequest { private String username; diff --git a/android/app/src/main/java/com/example/petstoremobile/dtos/AvatarUploadResponse.java b/android/app/src/main/java/com/example/petstoremobile/dtos/AvatarUploadResponse.java index 194be1f4..4495e05e 100644 --- a/android/app/src/main/java/com/example/petstoremobile/dtos/AvatarUploadResponse.java +++ b/android/app/src/main/java/com/example/petstoremobile/dtos/AvatarUploadResponse.java @@ -1,5 +1,8 @@ package com.example.petstoremobile.dtos; +/** + * Response containing the URL of a newly uploaded avatar. + */ public class AvatarUploadResponse { private String avatarUrl; private String message; diff --git a/android/app/src/main/java/com/example/petstoremobile/dtos/BulkDeleteRequest.java b/android/app/src/main/java/com/example/petstoremobile/dtos/BulkDeleteRequest.java index e53c8369..0fd6ae5a 100644 --- a/android/app/src/main/java/com/example/petstoremobile/dtos/BulkDeleteRequest.java +++ b/android/app/src/main/java/com/example/petstoremobile/dtos/BulkDeleteRequest.java @@ -2,6 +2,9 @@ package com.example.petstoremobile.dtos; import java.util.List; +/** + * Request body for deleting multiple records at once. + */ public class BulkDeleteRequest { private List ids; diff --git a/android/app/src/main/java/com/example/petstoremobile/dtos/CategoryDTO.java b/android/app/src/main/java/com/example/petstoremobile/dtos/CategoryDTO.java index 6596845b..b8c84b7c 100644 --- a/android/app/src/main/java/com/example/petstoremobile/dtos/CategoryDTO.java +++ b/android/app/src/main/java/com/example/petstoremobile/dtos/CategoryDTO.java @@ -1,5 +1,8 @@ package com.example.petstoremobile.dtos; +/** + * Data Transfer Object for product categories. + */ public class CategoryDTO { private Long categoryId; private String categoryName; diff --git a/android/app/src/main/java/com/example/petstoremobile/dtos/ConversationDTO.java b/android/app/src/main/java/com/example/petstoremobile/dtos/ConversationDTO.java index 3a7ea42e..135bd84d 100644 --- a/android/app/src/main/java/com/example/petstoremobile/dtos/ConversationDTO.java +++ b/android/app/src/main/java/com/example/petstoremobile/dtos/ConversationDTO.java @@ -1,5 +1,8 @@ package com.example.petstoremobile.dtos; +/** + * Data Transfer Object for chat conversations. + */ public class ConversationDTO { private Long id; private Long customerId; diff --git a/android/app/src/main/java/com/example/petstoremobile/dtos/CouponDTO.java b/android/app/src/main/java/com/example/petstoremobile/dtos/CouponDTO.java index e2ecb2c4..647d9baf 100644 --- a/android/app/src/main/java/com/example/petstoremobile/dtos/CouponDTO.java +++ b/android/app/src/main/java/com/example/petstoremobile/dtos/CouponDTO.java @@ -2,6 +2,9 @@ package com.example.petstoremobile.dtos; import java.math.BigDecimal; +/** + * Data Transfer Object for coupons. + */ public class CouponDTO { private Long couponId; private String couponCode; diff --git a/android/app/src/main/java/com/example/petstoremobile/dtos/CustomerDTO.java b/android/app/src/main/java/com/example/petstoremobile/dtos/CustomerDTO.java index c190342e..0872252c 100644 --- a/android/app/src/main/java/com/example/petstoremobile/dtos/CustomerDTO.java +++ b/android/app/src/main/java/com/example/petstoremobile/dtos/CustomerDTO.java @@ -2,6 +2,9 @@ package com.example.petstoremobile.dtos; import com.google.gson.annotations.SerializedName; +/** + * Data Transfer Object for customers. + */ public class CustomerDTO { @SerializedName("id") private Long customerId; diff --git a/android/app/src/main/java/com/example/petstoremobile/dtos/DropdownDTO.java b/android/app/src/main/java/com/example/petstoremobile/dtos/DropdownDTO.java index 3174dae5..3f46d119 100644 --- a/android/app/src/main/java/com/example/petstoremobile/dtos/DropdownDTO.java +++ b/android/app/src/main/java/com/example/petstoremobile/dtos/DropdownDTO.java @@ -1,5 +1,8 @@ package com.example.petstoremobile.dtos; +/** + * Data Transfer Object for simple dropdown selection lists. + */ public class DropdownDTO { private Long id; private String label; diff --git a/android/app/src/main/java/com/example/petstoremobile/dtos/EmployeeDTO.java b/android/app/src/main/java/com/example/petstoremobile/dtos/EmployeeDTO.java index f29b4beb..f7288d73 100644 --- a/android/app/src/main/java/com/example/petstoremobile/dtos/EmployeeDTO.java +++ b/android/app/src/main/java/com/example/petstoremobile/dtos/EmployeeDTO.java @@ -1,5 +1,8 @@ package com.example.petstoremobile.dtos; +/** + * Data Transfer Object for employees. + */ public class EmployeeDTO { private Long id; diff --git a/android/app/src/main/java/com/example/petstoremobile/dtos/ErrorResponse.java b/android/app/src/main/java/com/example/petstoremobile/dtos/ErrorResponse.java index ddb23eaa..56cc726c 100644 --- a/android/app/src/main/java/com/example/petstoremobile/dtos/ErrorResponse.java +++ b/android/app/src/main/java/com/example/petstoremobile/dtos/ErrorResponse.java @@ -1,7 +1,8 @@ package com.example.petstoremobile.dtos; -//Used to get messages of any errors from the backend - +/** + * Used to get messages of any errors from the backend. + */ public class ErrorResponse { private String message; diff --git a/android/app/src/main/java/com/example/petstoremobile/dtos/InventoryDTO.java b/android/app/src/main/java/com/example/petstoremobile/dtos/InventoryDTO.java index ddafd045..3fd6be57 100644 --- a/android/app/src/main/java/com/example/petstoremobile/dtos/InventoryDTO.java +++ b/android/app/src/main/java/com/example/petstoremobile/dtos/InventoryDTO.java @@ -1,5 +1,8 @@ package com.example.petstoremobile.dtos; +/** + * Data Transfer Object for inventory stock. + */ public class InventoryDTO { // Response fields (from backend InventoryResponse) private Long inventoryId; diff --git a/android/app/src/main/java/com/example/petstoremobile/dtos/MessageDTO.java b/android/app/src/main/java/com/example/petstoremobile/dtos/MessageDTO.java index 8302ba86..17b54fa8 100644 --- a/android/app/src/main/java/com/example/petstoremobile/dtos/MessageDTO.java +++ b/android/app/src/main/java/com/example/petstoremobile/dtos/MessageDTO.java @@ -2,6 +2,9 @@ package com.example.petstoremobile.dtos; import com.google.gson.annotations.SerializedName; +/** + * Data Transfer Object for chat messages. + */ public class MessageDTO { @SerializedName("id") diff --git a/android/app/src/main/java/com/example/petstoremobile/dtos/PageResponse.java b/android/app/src/main/java/com/example/petstoremobile/dtos/PageResponse.java index 7237105e..56558e15 100644 --- a/android/app/src/main/java/com/example/petstoremobile/dtos/PageResponse.java +++ b/android/app/src/main/java/com/example/petstoremobile/dtos/PageResponse.java @@ -2,7 +2,9 @@ package com.example.petstoremobile.dtos; import java.util.List; -//Used to get data from the API +/** + * Generic response wrapper for paginated API results. + */ public class PageResponse { private List content; private int totalPages; diff --git a/android/app/src/main/java/com/example/petstoremobile/dtos/PetDTO.java b/android/app/src/main/java/com/example/petstoremobile/dtos/PetDTO.java index 0e9a0b3f..3a3314d5 100644 --- a/android/app/src/main/java/com/example/petstoremobile/dtos/PetDTO.java +++ b/android/app/src/main/java/com/example/petstoremobile/dtos/PetDTO.java @@ -1,5 +1,8 @@ package com.example.petstoremobile.dtos; +/** + * Data Transfer Object representing a pet. + */ public class PetDTO { private Long petId; private String petName; diff --git a/android/app/src/main/java/com/example/petstoremobile/dtos/ProductDTO.java b/android/app/src/main/java/com/example/petstoremobile/dtos/ProductDTO.java index 2b016b28..c95f0a32 100644 --- a/android/app/src/main/java/com/example/petstoremobile/dtos/ProductDTO.java +++ b/android/app/src/main/java/com/example/petstoremobile/dtos/ProductDTO.java @@ -2,6 +2,9 @@ package com.example.petstoremobile.dtos; import java.math.BigDecimal; +/** + * Data Transfer Object for products. + */ public class ProductDTO { private Long prodId; private String prodName; diff --git a/android/app/src/main/java/com/example/petstoremobile/dtos/ProductSupplierDTO.java b/android/app/src/main/java/com/example/petstoremobile/dtos/ProductSupplierDTO.java index 887d29e1..e25f82ec 100644 --- a/android/app/src/main/java/com/example/petstoremobile/dtos/ProductSupplierDTO.java +++ b/android/app/src/main/java/com/example/petstoremobile/dtos/ProductSupplierDTO.java @@ -2,6 +2,9 @@ package com.example.petstoremobile.dtos; import java.math.BigDecimal; +/** + * Data Transfer Object for mapping products to suppliers. + */ public class ProductSupplierDTO { private Long productId; private String productName; diff --git a/android/app/src/main/java/com/example/petstoremobile/dtos/PurchaseOrderDTO.java b/android/app/src/main/java/com/example/petstoremobile/dtos/PurchaseOrderDTO.java index 813633c9..eb760e59 100644 --- a/android/app/src/main/java/com/example/petstoremobile/dtos/PurchaseOrderDTO.java +++ b/android/app/src/main/java/com/example/petstoremobile/dtos/PurchaseOrderDTO.java @@ -1,5 +1,8 @@ package com.example.petstoremobile.dtos; +/** + * Data Transfer Object for purchase orders. + */ public class PurchaseOrderDTO { private Long purchaseOrderId; private Long supId; diff --git a/android/app/src/main/java/com/example/petstoremobile/dtos/RefundDTO.java b/android/app/src/main/java/com/example/petstoremobile/dtos/RefundDTO.java index 5f47e1ce..dc3d2d67 100644 --- a/android/app/src/main/java/com/example/petstoremobile/dtos/RefundDTO.java +++ b/android/app/src/main/java/com/example/petstoremobile/dtos/RefundDTO.java @@ -2,6 +2,9 @@ package com.example.petstoremobile.dtos; import java.math.BigDecimal; +/** + * Data Transfer Object for refund processing. + */ public class RefundDTO { // Response fields private Long id; diff --git a/android/app/src/main/java/com/example/petstoremobile/dtos/SaleDTO.java b/android/app/src/main/java/com/example/petstoremobile/dtos/SaleDTO.java index 9dc76029..d8501995 100644 --- a/android/app/src/main/java/com/example/petstoremobile/dtos/SaleDTO.java +++ b/android/app/src/main/java/com/example/petstoremobile/dtos/SaleDTO.java @@ -3,6 +3,9 @@ package com.example.petstoremobile.dtos; import java.math.BigDecimal; import java.util.List; +/** + * Data Transfer Object for sales transactions. + */ public class SaleDTO { // Response fields private Long saleId; diff --git a/android/app/src/main/java/com/example/petstoremobile/dtos/SendMessageRequest.java b/android/app/src/main/java/com/example/petstoremobile/dtos/SendMessageRequest.java index 7a521de3..aab51a90 100644 --- a/android/app/src/main/java/com/example/petstoremobile/dtos/SendMessageRequest.java +++ b/android/app/src/main/java/com/example/petstoremobile/dtos/SendMessageRequest.java @@ -1,5 +1,8 @@ package com.example.petstoremobile.dtos; +/** + * Request body for sending a new chat message. + */ public class SendMessageRequest { private String content; diff --git a/android/app/src/main/java/com/example/petstoremobile/dtos/ServiceDTO.java b/android/app/src/main/java/com/example/petstoremobile/dtos/ServiceDTO.java index 56e44371..cfbacb8e 100644 --- a/android/app/src/main/java/com/example/petstoremobile/dtos/ServiceDTO.java +++ b/android/app/src/main/java/com/example/petstoremobile/dtos/ServiceDTO.java @@ -1,5 +1,8 @@ package com.example.petstoremobile.dtos; +/** + * Data Transfer Object for services. + */ public class ServiceDTO { private Long serviceId; private String serviceName; diff --git a/android/app/src/main/java/com/example/petstoremobile/dtos/StoreDTO.java b/android/app/src/main/java/com/example/petstoremobile/dtos/StoreDTO.java index da66f046..ba4d732a 100644 --- a/android/app/src/main/java/com/example/petstoremobile/dtos/StoreDTO.java +++ b/android/app/src/main/java/com/example/petstoremobile/dtos/StoreDTO.java @@ -1,5 +1,8 @@ package com.example.petstoremobile.dtos; +/** + * Data Transfer Object for store information. + */ public class StoreDTO { private Long storeId; private String storeName; diff --git a/android/app/src/main/java/com/example/petstoremobile/dtos/SupplierDTO.java b/android/app/src/main/java/com/example/petstoremobile/dtos/SupplierDTO.java index e34816c1..e39d22c8 100644 --- a/android/app/src/main/java/com/example/petstoremobile/dtos/SupplierDTO.java +++ b/android/app/src/main/java/com/example/petstoremobile/dtos/SupplierDTO.java @@ -1,5 +1,8 @@ package com.example.petstoremobile.dtos; +/** + * Data Transfer Object for suppliers. + */ public class SupplierDTO { private Long supId; private String supCompany; diff --git a/android/app/src/main/java/com/example/petstoremobile/dtos/UpdateConversationStatusRequest.java b/android/app/src/main/java/com/example/petstoremobile/dtos/UpdateConversationStatusRequest.java index 4d7987e1..e0fe3fe2 100644 --- a/android/app/src/main/java/com/example/petstoremobile/dtos/UpdateConversationStatusRequest.java +++ b/android/app/src/main/java/com/example/petstoremobile/dtos/UpdateConversationStatusRequest.java @@ -1,5 +1,8 @@ package com.example.petstoremobile.dtos; +/** + * Request body for updating chat conversation status. + */ public class UpdateConversationStatusRequest { private String status; diff --git a/android/app/src/main/java/com/example/petstoremobile/dtos/UserDTO.java b/android/app/src/main/java/com/example/petstoremobile/dtos/UserDTO.java index 2ab9902e..05866080 100644 --- a/android/app/src/main/java/com/example/petstoremobile/dtos/UserDTO.java +++ b/android/app/src/main/java/com/example/petstoremobile/dtos/UserDTO.java @@ -1,5 +1,8 @@ package com.example.petstoremobile.dtos; +/** + * Data Transfer Object for user account details. + */ public class UserDTO { private Long id; private String username; diff --git a/android/app/src/main/java/com/example/petstoremobile/fragments/ChatFragment.java b/android/app/src/main/java/com/example/petstoremobile/fragments/ChatFragment.java index 88bb0f09..83678a68 100644 --- a/android/app/src/main/java/com/example/petstoremobile/fragments/ChatFragment.java +++ b/android/app/src/main/java/com/example/petstoremobile/fragments/ChatFragment.java @@ -65,6 +65,9 @@ import okhttp3.MultipartBody; import okhttp3.RequestBody; import okhttp3.ResponseBody; +/** + * Fragment for handling customer support chat. + */ @AndroidEntryPoint public class ChatFragment extends Fragment implements ChatAdapter.OnChatClickListener, StompChatManager.MessageListener, StompChatManager.ConversationListener, StompChatManager.ConnectionListener { @@ -90,6 +93,9 @@ public class ChatFragment extends Fragment implements ChatAdapter.OnChatClickLis private StompChatManager stompChatManager; private ActivityResultLauncher attachmentLauncher; + /** + * Initializes the view model and attachment launcher. + */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -105,6 +111,9 @@ public class ChatFragment extends Fragment implements ChatAdapter.OnChatClickLis ); } + /** + * Inflates the layout and sets up UI event listeners. + */ @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -137,6 +146,9 @@ public class ChatFragment extends Fragment implements ChatAdapter.OnChatClickLis return binding.getRoot(); } + /** + * Sets up the logic to open and close the chat drawer. + */ private void setupDrawerToggles() { binding.headerActiveChats.setOnClickListener(v -> { if (binding.rvActiveChats.getVisibility() == View.VISIBLE) { @@ -159,6 +171,9 @@ public class ChatFragment extends Fragment implements ChatAdapter.OnChatClickLis }); } + /** + * Configures the adapters and layout managers for chat lists and message history. + */ private void setupRecyclerViews() { activeChatAdapter = new ChatAdapter(activeChatList, this); binding.rvActiveChats.setLayoutManager(new LinearLayoutManager(getContext())); @@ -187,6 +202,9 @@ public class ChatFragment extends Fragment implements ChatAdapter.OnChatClickLis setConversationActive(false, null); } + /** + * Displays a full-screen image preview for message attachments. + */ private void showFullScreenImage(Message message) { if (baseUrl == null || message.getId() == null) return; @@ -208,6 +226,9 @@ public class ChatFragment extends Fragment implements ChatAdapter.OnChatClickLis dialog.show(); } + /** + * Initiates the download process for a message attachment. + */ private void downloadFile(Message message) { if (message.getId() == null) return; @@ -227,6 +248,9 @@ public class ChatFragment extends Fragment implements ChatAdapter.OnChatClickLis }); } + /** + * Saves the downloaded file body to the device's downloads folder. + */ private void saveFileToDownloads(ResponseBody body, String fileName, String mimeType) { android.os.Handler mainHandler = new android.os.Handler(android.os.Looper.getMainLooper()); new Thread(() -> { @@ -270,6 +294,9 @@ public class ChatFragment extends Fragment implements ChatAdapter.OnChatClickLis }).start(); } + /** + * Observes LiveData from the ViewModel to update chat lists and messages. + */ private void observeViewModel() { viewModel.getActiveChats().observe(getViewLifecycleOwner(), list -> { activeChatList.clear(); @@ -300,12 +327,18 @@ public class ChatFragment extends Fragment implements ChatAdapter.OnChatClickLis viewModel.getIsLoading().observe(getViewLifecycleOwner(), this::setLoading); } + /** + * Toggles the visibility of the progress bar. + */ private void setLoading(boolean loading) { if (binding != null && binding.progressBar != null) { binding.progressBar.setVisibility(loading ? View.VISIBLE : View.GONE); } } + /** + * Updates the chat header and input state if the active conversation changes. + */ private void updateTitleAndStateIfActive(List list) { if (activeConversationId != null) { for (Chat chat : list) { @@ -318,6 +351,9 @@ public class ChatFragment extends Fragment implements ChatAdapter.OnChatClickLis } } + /** + * Loads initial chat data and establishes WebSocket connection. + */ private void loadInitialData() { String token = tokenManager.getToken(); Long currentUserId = tokenManager.getUserId(); @@ -353,6 +389,9 @@ public class ChatFragment extends Fragment implements ChatAdapter.OnChatClickLis } } + /** + * Handles clicks on a chat from the drawer to switch the active conversation. + */ @Override public void onChatClick(Chat chat) { activeConversationId = Long.parseLong(chat.getChatId()); @@ -368,6 +407,9 @@ public class ChatFragment extends Fragment implements ChatAdapter.OnChatClickLis viewModel.loadMessageHistory(activeConversationId); } + /** + * Closes the active chat conversation. + */ private void closeChat() { if (activeConversationId == null) return; @@ -392,6 +434,9 @@ public class ChatFragment extends Fragment implements ChatAdapter.OnChatClickLis }); } + /** + * Sends a text message to the active conversation. + */ private void sendMessage() { if (activeConversationId == null) return; String text = binding.etMessage.getText().toString().trim(); @@ -408,12 +453,18 @@ public class ChatFragment extends Fragment implements ChatAdapter.OnChatClickLis }); } + /** + * Opens a file picker to select an attachment. + */ private void selectAttachment() { Intent intent = new Intent(Intent.ACTION_GET_CONTENT); intent.setType("*/*"); attachmentLauncher.launch(intent); } + /** + * Displays a preview of the selected attachment. + */ private void showAttachmentPreview(Uri uri) { pendingAttachmentUri = uri; binding.layoutAttachmentPreview.setVisibility(View.VISIBLE); @@ -427,11 +478,17 @@ public class ChatFragment extends Fragment implements ChatAdapter.OnChatClickLis } } + /** + * Removes the currently selected attachment from the preview. + */ private void removeAttachment() { pendingAttachmentUri = null; binding.layoutAttachmentPreview.setVisibility(View.GONE); } + /** + * Sends a message with a file attachment. + */ private void sendWithAttachment(Uri uri) { if (activeConversationId == null) return; @@ -468,6 +525,9 @@ public class ChatFragment extends Fragment implements ChatAdapter.OnChatClickLis }); } + /** + * Callback for when a new message is received through the WebSocket. + */ @Override public void onMessageReceived(MessageDTO dto) { requireActivity().runOnUiThread(() -> { @@ -478,6 +538,9 @@ public class ChatFragment extends Fragment implements ChatAdapter.OnChatClickLis }); } + /** + * Callback for when a conversation's status or last message is updated. + */ @Override public void onConversationUpdated(ConversationDTO dto) { requireActivity().runOnUiThread(() -> { @@ -489,6 +552,9 @@ public class ChatFragment extends Fragment implements ChatAdapter.OnChatClickLis }); } + /** + * Callback for when the WebSocket connection is successfully opened. + */ @Override public void onSocketOpened() { if (!isAdded()) return; @@ -498,12 +564,18 @@ public class ChatFragment extends Fragment implements ChatAdapter.OnChatClickLis }); } + /** + * Callback for when the WebSocket connection is closed. + */ @Override public void onSocketClosed() { if (!isAdded()) return; requireActivity().runOnUiThread(viewModel::loadConversations); } + /** + * Callback for when a WebSocket error occurs. + */ @Override public void onSocketError() { if (!isAdded()) return; @@ -513,6 +585,9 @@ public class ChatFragment extends Fragment implements ChatAdapter.OnChatClickLis }); } + /** + * Scrolls the message list to the most recent message. + */ private void scrollToBottom() { if (!messageList.isEmpty()) { binding.rvMessages.post(() -> @@ -520,6 +595,9 @@ public class ChatFragment extends Fragment implements ChatAdapter.OnChatClickLis } } + /** + * Updates the UI state based on whether a conversation is active and its status. + */ private void setConversationActive(boolean active, String status) { boolean isClosed = "CLOSED".equalsIgnoreCase(status); UIUtils.setViewsEnabled(active && !isClosed, binding.btnSend, binding.etMessage, binding.btnAttach); @@ -541,6 +619,9 @@ public class ChatFragment extends Fragment implements ChatAdapter.OnChatClickLis } } + /** + * Cleans up resources and disconnects the WebSocket when the view is destroyed. + */ @Override public void onDestroyView() { super.onDestroyView(); diff --git a/android/app/src/main/java/com/example/petstoremobile/fragments/ListFragment.java b/android/app/src/main/java/com/example/petstoremobile/fragments/ListFragment.java index 6f2c643b..8c3f3c2e 100644 --- a/android/app/src/main/java/com/example/petstoremobile/fragments/ListFragment.java +++ b/android/app/src/main/java/com/example/petstoremobile/fragments/ListFragment.java @@ -23,7 +23,9 @@ import javax.inject.Inject; import dagger.hilt.android.AndroidEntryPoint; -//The Fragment for the displaying the list of entities to be viewed +/** + * Fragment that serves as a container for various list-based screens, providing a navigation drawer. + */ @AndroidEntryPoint public class ListFragment extends Fragment { @@ -97,6 +99,9 @@ public class ListFragment extends Fragment { return binding.getRoot(); } + /** + * Cleans up the binding when the view is destroyed. + */ @Override public void onDestroyView() { super.onDestroyView(); diff --git a/android/app/src/main/java/com/example/petstoremobile/fragments/ProfileFragment.java b/android/app/src/main/java/com/example/petstoremobile/fragments/ProfileFragment.java index 7f8fc039..fb1decb7 100644 --- a/android/app/src/main/java/com/example/petstoremobile/fragments/ProfileFragment.java +++ b/android/app/src/main/java/com/example/petstoremobile/fragments/ProfileFragment.java @@ -173,12 +173,18 @@ public class ProfileFragment extends Fragment { return binding.getRoot(); } + /** + * Toggles the visibility of the progress bar. + */ private void setLoading(boolean loading) { if (binding != null && binding.progressBar != null) { binding.progressBar.setVisibility(loading ? View.VISIBLE : View.GONE); } } + /** + * Cleans up the binding when the view is destroyed. + */ @Override public void onDestroyView() { super.onDestroyView(); diff --git a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/ActivityLogFragment.java b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/ActivityLogFragment.java index f369d383..6dab8ec3 100644 --- a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/ActivityLogFragment.java +++ b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/ActivityLogFragment.java @@ -34,6 +34,9 @@ import java.util.List; import dagger.hilt.android.AndroidEntryPoint; +/** + * Fragment for viewing application activity logs with various filtering options. + */ @AndroidEntryPoint public class ActivityLogFragment extends Fragment { private FragmentActivityLogBinding binding; @@ -46,6 +49,9 @@ public class ActivityLogFragment extends Fragment { @Inject TokenManager tokenManager; + /** + * Inflates the layout, checks for admin access, and initializes ViewModel and UI components. + */ @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -69,12 +75,18 @@ public class ActivityLogFragment extends Fragment { return binding.getRoot(); } + /** + * Triggers initial data loading after the view is created. + */ @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); viewModel.loadInitialData(); } + /** + * Configures the RecyclerView and its scroll listener for pagination. + */ private void setupRecyclerView() { adapter = new ActivityLogAdapter(logList); binding.recyclerViewActivityLog.setLayoutManager(new LinearLayoutManager(getContext())); @@ -97,6 +109,9 @@ public class ActivityLogFragment extends Fragment { }); } + /** + * Sets up filters for logs, including search, role, store, and date range. + */ private void setupFilters() { UIUtils.setupFilterToggle(binding.btnToggleFilter, binding.layoutFilter, binding.etSearchLog, binding.spinnerRoleFilter, binding.spinnerStoreFilter); @@ -123,6 +138,9 @@ public class ActivityLogFragment extends Fragment { }); } + /** + * Displays a date picker dialog and updates the selected start or end date. + */ private void showDatePicker(boolean isStart) { Calendar cal = Calendar.getInstance(); new DatePickerDialog(requireContext(), (view, year, month, day) -> { @@ -141,12 +159,18 @@ public class ActivityLogFragment extends Fragment { }, cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH)).show(); } + /** + * Handles store selection from the filter spinner. + */ private void onStoreSelected() { int pos = binding.spinnerStoreFilter.getSelectedItemPosition(); Long storeId = (pos > 0 && !storeList.isEmpty()) ? storeList.get(pos - 1).getId() : null; viewModel.setStoreFilter(storeId); } + /** + * Observes the ViewModel for log list updates, store options, and loading status. + */ private void observeViewModel() { viewModel.getLogs().observe(getViewLifecycleOwner(), list -> { logList.clear(); @@ -164,6 +188,9 @@ public class ActivityLogFragment extends Fragment { binding.swipeRefreshActivityLog.setRefreshing(loading)); } + /** + * Cleans up the binding reference. + */ @Override public void onDestroyView() { super.onDestroyView(); diff --git a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/AdoptionFragment.java b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/AdoptionFragment.java index a6ba396e..fd4209f1 100644 --- a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/AdoptionFragment.java +++ b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/AdoptionFragment.java @@ -44,6 +44,9 @@ import javax.inject.Inject; import dagger.hilt.android.AndroidEntryPoint; +/** + * Fragment for displaying and managing a list of adoptions with a calendar view and filtering. + */ @AndroidEntryPoint public class AdoptionFragment extends Fragment implements AdoptionAdapter.OnAdoptionClickListener { @@ -58,12 +61,18 @@ public class AdoptionFragment extends Fragment implements AdoptionAdapter.OnAdop @Inject TokenManager tokenManager; + /** + * Initializes the ViewModel. + */ @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); viewModel = new ViewModelProvider(this).get(AdoptionListViewModel.class); } + /** + * Inflates the layout and sets up UI components, calendar, and observers. + */ @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -88,6 +97,9 @@ public class AdoptionFragment extends Fragment implements AdoptionAdapter.OnAdop return binding.getRoot(); } + /** + * Observes the ViewModel for adoption list, stores, and loading status. + */ private void observeViewModel() { viewModel.getAdoptions().observe(getViewLifecycleOwner(), list -> { adoptionList.clear(); @@ -106,6 +118,9 @@ public class AdoptionFragment extends Fragment implements AdoptionAdapter.OnAdop }); } + /** + * Configures the bulk delete handler for multiple adoption record deletion. + */ private void setupBulkDelete() { bulkDeleteHandler = new BulkDeleteHandler( this, @@ -119,6 +134,9 @@ public class AdoptionFragment extends Fragment implements AdoptionAdapter.OnAdop ); } + /** + * Reloads adoption data and stores when the fragment resumes. + */ @Override public void onResume() { super.onResume(); @@ -126,6 +144,9 @@ public class AdoptionFragment extends Fragment implements AdoptionAdapter.OnAdop if (!isStaff()) viewModel.loadStores(); } + /** + * Toggles between month and week display modes for the calendar. + */ private void toggleCalendarMode() { isMonthMode = !isMonthMode; binding.calendarViewAdoption.state().edit() @@ -133,6 +154,9 @@ public class AdoptionFragment extends Fragment implements AdoptionAdapter.OnAdop .commit(); } + /** + * Sets up the filter visibility toggle, considering user roles. + */ private void setupFilterToggle() { if (isStaff()) { UIUtils.setupFilterToggle(binding.btnToggleFilterAdoption, binding.layoutFilterAdoption, @@ -144,10 +168,16 @@ public class AdoptionFragment extends Fragment implements AdoptionAdapter.OnAdop } } + /** + * Checks if the currently logged-in user has the STAFF role. + */ private boolean isStaff() { return "STAFF".equalsIgnoreCase(tokenManager.getRole()); } + /** + * Configures the calendar view for date-based filtering. + */ private void setupCalendar() { binding.calendarViewAdoption.setOnDateChangedListener((widget, date, selected) -> { if (selected) { @@ -164,6 +194,9 @@ public class AdoptionFragment extends Fragment implements AdoptionAdapter.OnAdop }); } + /** + * Updates calendar decorators to highlight dates with adoptions. + */ private void updateCalendarDecorators() { HashSet datesWithAdoptions = new HashSet<>(); for (AdoptionDTO adoption : adoptionList) { @@ -184,6 +217,9 @@ public class AdoptionFragment extends Fragment implements AdoptionAdapter.OnAdop binding.calendarViewAdoption.addDecorator(new EventDecorator(Color.RED, datesWithAdoptions)); } + /** + * Configures the RecyclerView and its scroll listener for pagination. + */ private void setupRecyclerView() { adapter = new AdoptionAdapter(adoptionList, this); binding.recyclerViewAdoptions.setLayoutManager(new LinearLayoutManager(getContext())); @@ -206,23 +242,38 @@ public class AdoptionFragment extends Fragment implements AdoptionAdapter.OnAdop }); } + /** + * Sets up the search input listener. + */ private void setupSearch() { UIUtils.attachSearch(binding.etSearchAdoption, () -> loadAdoptions(true)); } + /** + * Configures the status filter spinner. + */ private void setupStatusFilter() { String[] statuses = {"All Statuses", "Completed", "Pending", "Missed", "Cancelled"}; SpinnerUtils.setupStringFilterSpinner(requireContext(), binding.spinnerStatusAdoption, statuses, () -> loadAdoptions(true)); } + /** + * Configures the store filter spinner. + */ private void setupStoreFilter() { SpinnerUtils.setupFilterSpinner(binding.spinnerStoreAdoption, () -> loadAdoptions(true)); } + /** + * Configures the swipe-to-refresh layout. + */ private void setupSwipeRefresh() { binding.swipeRefreshAdoption.setOnRefreshListener(() -> loadAdoptions(true)); } + /** + * Loads adoption data based on current filters, search query, and selected date. + */ private void loadAdoptions(boolean reset) { String query = binding.etSearchAdoption.getText().toString().trim(); String status = binding.spinnerStatusAdoption.getSelectedItem() != null ? binding.spinnerStatusAdoption.getSelectedItem().toString() : "All Statuses"; @@ -250,6 +301,9 @@ public class AdoptionFragment extends Fragment implements AdoptionAdapter.OnAdop viewModel.loadAdoptions(reset, query, status, storeId, selectedDateString, null); } + /** + * Navigates to the adoption detail screen. + */ private void openDetail(int position) { Bundle args = new Bundle(); if (position != -1) { @@ -259,9 +313,15 @@ public class AdoptionFragment extends Fragment implements AdoptionAdapter.OnAdop NavHostFragment.findNavController(this).navigate(R.id.nav_adoption_detail, args); } + /** + * Handles adoption item clicks by opening details. + */ @Override public void onAdoptionClick(int position) { openDetail(position); } + /** + * Forwards selection changes to the bulk delete handler. + */ @Override public void onSelectionChanged(int selectedCount) { if (bulkDeleteHandler != null) { @@ -269,6 +329,9 @@ public class AdoptionFragment extends Fragment implements AdoptionAdapter.OnAdop } } + /** + * Cleans up the binding reference. + */ @Override public void onDestroyView() { super.onDestroyView(); diff --git a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/AnalyticsFragment.java b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/AnalyticsFragment.java index 89aeb098..e493b0e3 100644 --- a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/AnalyticsFragment.java +++ b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/AnalyticsFragment.java @@ -18,6 +18,9 @@ import java.math.BigDecimal; import java.math.RoundingMode; import java.util.*; +/** + * Fragment for displaying business analytics, including revenue, transactions, and product performance. + */ @AndroidEntryPoint public class AnalyticsFragment extends Fragment { @@ -31,6 +34,9 @@ public class AnalyticsFragment extends Fragment { private static final String[] TOP_N_OPTIONS = {"5", "10", "15", "20"}; private static final int[] TOP_N_VALUES = { 5, 10, 15, 20 }; + /** + * Inflates the layout, initializes ViewModel, and sets up UI components and filters. + */ @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -51,6 +57,9 @@ public class AnalyticsFragment extends Fragment { private static final int COLOR_SELECTED = 0xFF4ECDC4; private static final int COLOR_UNSELECTED = 0xFFCBD5E1; + /** + * Configures the view mode toggle buttons (My Analytics vs Store Analytics). + */ private void setupViewModeToggle() { updateViewModeButtonStyles(viewModel.getViewMode()); @@ -67,6 +76,9 @@ public class AnalyticsFragment extends Fragment { }); } + /** + * Updates the styles of the view mode buttons based on the selected mode. + */ private void updateViewModeButtonStyles(String mode) { binding.btnMyAnalytics.setBackgroundTintList( android.content.res.ColorStateList.valueOf(mode.equals("mine") ? COLOR_SELECTED : COLOR_UNSELECTED)); @@ -74,6 +86,9 @@ public class AnalyticsFragment extends Fragment { android.content.res.ColorStateList.valueOf(mode.equals("store") ? COLOR_SELECTED : COLOR_UNSELECTED)); } + /** + * Updates the visibility of the store filter based on the user's role and selected view mode. + */ private void updateStoreFilterVisibility(String mode) { boolean isAdmin = "ADMIN".equalsIgnoreCase(tokenManager.getRole()); int vis = (isAdmin && mode.equals("store")) ? View.VISIBLE : View.GONE; @@ -81,8 +96,10 @@ public class AnalyticsFragment extends Fragment { binding.spinnerFilterStore.setVisibility(vis); } - // Filter Panel + /** + * Configures the filter panel, including date pickers, presets, and action buttons. + */ private void setupFilterPanel() { SpinnerUtils.setupStringSpinner(requireContext(), binding.spinnerTopN, TOP_N_OPTIONS); @@ -111,12 +128,18 @@ public class AnalyticsFragment extends Fragment { binding.btnFilterReset.setOnClickListener(v -> resetFilters()); } + /** + * Toggles the visibility of the filter content section. + */ private void toggleFilters() { filtersExpanded = !filtersExpanded; binding.llFilterContent.setVisibility(filtersExpanded ? View.VISIBLE : View.GONE); binding.tvFilterToggleIcon.setText(filtersExpanded ? "▲" : "▼"); } + /** + * Applies a date range preset to the filter fields. + */ private void applyPreset(int startOffset, int endOffset) { binding.etFilterStartDate.setText(getDateString(startOffset)); binding.etFilterEndDate.setText(getDateString(endOffset)); @@ -124,6 +147,9 @@ public class AnalyticsFragment extends Fragment { applyFiltersFromUI(); } + /** + * Reads filter values from the UI and applies them to the ViewModel. + */ private void applyFiltersFromUI() { AnalyticsViewModel.FilterState filter = new AnalyticsViewModel.FilterState(); filter.startDate = binding.etFilterStartDate.getText().toString().trim(); @@ -142,6 +168,9 @@ public class AnalyticsFragment extends Fragment { viewModel.applyFilter(filter); } + /** + * Resets all filters to their default values. + */ private void resetFilters() { binding.etFilterStartDate.setText(""); binding.etFilterEndDate.setText(""); @@ -152,6 +181,9 @@ public class AnalyticsFragment extends Fragment { viewModel.resetFilter(); } + /** + * Updates the text summary of the currently selected date range. + */ private void updateFilterSummary() { String start = binding.etFilterStartDate.getText().toString().trim(); String end = binding.etFilterEndDate.getText().toString().trim(); @@ -166,10 +198,16 @@ public class AnalyticsFragment extends Fragment { } } + /** + * Formats a date string into a shorter version for display. + */ private String shortDate(String date) { return (date != null && date.length() >= 10) ? date.substring(5) : date; } + /** + * Returns a formatted date string for a given day. + */ private String getDateString(int offsetDays) { Calendar c = Calendar.getInstance(); c.add(Calendar.DAY_OF_YEAR, offsetDays); @@ -177,8 +215,10 @@ public class AnalyticsFragment extends Fragment { c.get(Calendar.YEAR), c.get(Calendar.MONTH) + 1, c.get(Calendar.DAY_OF_MONTH)); } - // ViewModel Observation + /** + * Observes the ViewModel for analytics data, loading status, errors, and filter options. + */ private void observeViewModel() { viewModel.getAnalyticsData().observe(getViewLifecycleOwner(), this::computeAndDisplay); @@ -216,14 +256,19 @@ public class AnalyticsFragment extends Fragment { }); } + /** + * Cleans up the binding reference. + */ @Override public void onDestroyView() { super.onDestroyView(); binding = null; } - // Display + /** + * Computes and displays analytics data in summary cards and bar charts. + */ private void computeAndDisplay(AnalyticsViewModel.AnalyticsData data) { if (data == null) return; @@ -312,8 +357,10 @@ public class AnalyticsFragment extends Fragment { } } - // Chart Helpers + /** + * Dynamically adds a bar chart row to a given layout container. + */ private void addBarRow(LinearLayout parent, String label, String value, float ratio, String color) { if (getContext() == null) return; LinearLayout row = new LinearLayout(getContext()); @@ -359,6 +406,9 @@ public class AnalyticsFragment extends Fragment { parent.addView(row); } + /** + * Adds an empty message row to a given layout container. + */ private void addEmptyRow(LinearLayout parent, String message) { if (getContext() == null) return; TextView tv = new TextView(getContext()); @@ -368,6 +418,9 @@ public class AnalyticsFragment extends Fragment { parent.addView(tv); } + /** + * Displays an error message and updates UI to reflect the error state. + */ private void showError(String msg) { if (getContext() == null || binding == null) return; binding.tvTotalRevenue.setText("Error"); diff --git a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/AppointmentFragment.java b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/AppointmentFragment.java index b8196775..99530081 100644 --- a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/AppointmentFragment.java +++ b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/AppointmentFragment.java @@ -45,6 +45,9 @@ import javax.inject.Inject; import dagger.hilt.android.AndroidEntryPoint; +/** + * Fragment for displaying and managing a list of appointments with calendar integration and filtering. + */ @AndroidEntryPoint public class AppointmentFragment extends Fragment implements AppointmentAdapter.OnAppointmentClickListener { @@ -63,6 +66,9 @@ public class AppointmentFragment extends Fragment implements AppointmentAdapter. private Long currentUserId = null; private final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()); + /** + * Initializes ViewModels for appointment and authentication data. + */ @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -70,6 +76,9 @@ public class AppointmentFragment extends Fragment implements AppointmentAdapter. authViewModel = new ViewModelProvider(this).get(AuthViewModel.class); } + /** + * Inflates the layout and sets up UI components, calendar, and observers. + */ @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -97,6 +106,9 @@ public class AppointmentFragment extends Fragment implements AppointmentAdapter. return binding.getRoot(); } + /** + * Observes the ViewModel for appointment list, stores, and loading status. + */ private void observeViewModel() { viewModel.getAppointments().observe(getViewLifecycleOwner(), list -> { appointmentList.clear(); @@ -115,6 +127,9 @@ public class AppointmentFragment extends Fragment implements AppointmentAdapter. }); } + /** + * Configures the bulk delete handler for multiple appointment deletion. + */ private void setupBulkDelete() { bulkDeleteHandler = new BulkDeleteHandler( this, @@ -128,6 +143,9 @@ public class AppointmentFragment extends Fragment implements AppointmentAdapter. ); } + /** + * Reloads appointment data and stores when the fragment resumes. + */ @Override public void onResume() { super.onResume(); @@ -135,6 +153,9 @@ public class AppointmentFragment extends Fragment implements AppointmentAdapter. if (!isStaff()) viewModel.loadStores(); } + /** + * Toggles between month and week display modes for the calendar. + */ private void toggleCalendarMode() { isMonthMode = !isMonthMode; binding.calendarView.state().edit() @@ -142,12 +163,18 @@ public class AppointmentFragment extends Fragment implements AppointmentAdapter. .commit(); } + /** + * Sets up the "My Appointments" filter button. + */ private void setupMyAppointmentFilter() { binding.btnMyAppointments.setOnClickListener(v -> { loadAppointmentData(true); }); } + /** + * Loads information about the currently logged-in user. + */ private void loadCurrentUserInfo() { authViewModel.getMe().observe(getViewLifecycleOwner(), resource -> { if (resource.status == Resource.Status.SUCCESS && resource.data != null) { @@ -156,6 +183,9 @@ public class AppointmentFragment extends Fragment implements AppointmentAdapter. }); } + /** + * Sets up the filter visibility toggle. + */ private void setupFilterToggle() { if (isStaff()) { UIUtils.setupFilterToggle(binding.btnToggleFilter, binding.layoutFilter, binding.etSearchAppointment, binding.spinnerStatus); @@ -166,6 +196,9 @@ public class AppointmentFragment extends Fragment implements AppointmentAdapter. } } + /** + * Configures the calendar view for date-based filtering. + */ private void setupCalendar() { binding.calendarView.setOnDateChangedListener((widget, date, selected) -> { if (selected) { @@ -182,6 +215,9 @@ public class AppointmentFragment extends Fragment implements AppointmentAdapter. }); } + /** + * Updates calendar decorators to highlight dates with appointments. + */ private void updateCalendarDecorators() { HashSet datesWithAppointments = new HashSet<>(); for (AppointmentDTO appointment : appointmentList) { @@ -200,23 +236,38 @@ public class AppointmentFragment extends Fragment implements AppointmentAdapter. binding.calendarView.addDecorator(new EventDecorator(Color.RED, datesWithAppointments)); } + /** + * Sets up the search input listener. + */ private void setupSearch() { UIUtils.attachSearch(binding.etSearchAppointment, () -> loadAppointmentData(true)); } + /** + * Configures the status filter spinner. + */ private void setupStatusFilter() { String[] statuses = {"All Statuses", "Booked", "Completed", "Cancelled", "Missed"}; SpinnerUtils.setupStringFilterSpinner(requireContext(), binding.spinnerStatus, statuses, () -> loadAppointmentData(true)); } + /** + * Configures the store filter spinner. + */ private void setupStoreFilter() { SpinnerUtils.setupFilterSpinner(binding.spinnerStore, () -> loadAppointmentData(true)); } + /** + * Configures the swipe-to-refresh layout. + */ private void setupSwipeRefresh() { binding.swipeRefreshAppointment.setOnRefreshListener(() -> loadAppointmentData(true)); } + /** + * Navigates to the appointment detail screen. + */ private void openAppointmentDetails(int position) { Bundle args = new Bundle(); if (position != -1) { @@ -226,11 +277,17 @@ public class AppointmentFragment extends Fragment implements AppointmentAdapter. NavHostFragment.findNavController(this).navigate(R.id.nav_appointment_detail, args); } + /** + * Handles appointment item clicks by opening details. + */ @Override public void onAppointmentClick(int position) { openAppointmentDetails(position); } + /** + * Forwards selection changes to the bulk delete handler. + */ @Override public void onSelectionChanged(int count) { if (bulkDeleteHandler != null) { @@ -238,10 +295,16 @@ public class AppointmentFragment extends Fragment implements AppointmentAdapter. } } + /** + * Checks if the currently logged-in user has the STAFF role. + */ private boolean isStaff() { return "STAFF".equalsIgnoreCase(tokenManager.getRole()); } + /** + * Loads appointment data based on current filters, search query, and selected date. + */ private void loadAppointmentData(boolean reset) { String query = binding.etSearchAppointment.getText().toString().trim(); String status = binding.spinnerStatus.getSelectedItem() != null ? binding.spinnerStatus.getSelectedItem().toString() : "All Statuses"; @@ -274,6 +337,9 @@ public class AppointmentFragment extends Fragment implements AppointmentAdapter. viewModel.loadAppointments(reset, query, status, storeId, selectedDateString, employeeId); } + /** + * Configures the RecyclerView and its scroll listener for pagination. + */ private void setupRecyclerView() { adapter = new AppointmentAdapter(appointmentList, this); binding.recyclerViewAppointments.setLayoutManager(new LinearLayoutManager(getContext())); @@ -296,6 +362,9 @@ public class AppointmentFragment extends Fragment implements AppointmentAdapter. }); } + /** + * Cleans up the binding reference. + */ @Override public void onDestroyView() { super.onDestroyView(); diff --git a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/CouponFragment.java b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/CouponFragment.java index c0beebfe..9bc754b4 100644 --- a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/CouponFragment.java +++ b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/CouponFragment.java @@ -27,6 +27,9 @@ import java.util.List; import dagger.hilt.android.AndroidEntryPoint; +/** + * Fragment for displaying and managing a list of coupons. + */ @AndroidEntryPoint public class CouponFragment extends Fragment implements CouponAdapter.OnCouponClickListener { private FragmentCouponBinding binding; @@ -34,6 +37,9 @@ public class CouponFragment extends Fragment implements CouponAdapter.OnCouponCl private CouponAdapter adapter; private final List couponList = new ArrayList<>(); + /** + * Inflates the layout, initializes ViewModel, and sets up UI components. + */ @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -59,6 +65,9 @@ public class CouponFragment extends Fragment implements CouponAdapter.OnCouponCl return binding.getRoot(); } + /** + * Observes the ViewModel for coupon list updates and loading status. + */ private void observeViewModel() { viewModel.getCoupons().observe(getViewLifecycleOwner(), list -> { couponList.clear(); @@ -71,6 +80,9 @@ public class CouponFragment extends Fragment implements CouponAdapter.OnCouponCl }); } + /** + * Configures the RecyclerView and its scroll listener for pagination. + */ private void setupRecyclerView() { adapter = new CouponAdapter(couponList, this); binding.recyclerViewCoupon.setLayoutManager(new LinearLayoutManager(getContext())); @@ -93,24 +105,39 @@ public class CouponFragment extends Fragment implements CouponAdapter.OnCouponCl }); } + /** + * Configures the status filter spinner. + */ private void setupStatusFilter() { String[] statuses = {"All Statuses", "Active", "Inactive"}; SpinnerUtils.setupStringFilterSpinner(requireContext(), binding.spinnerStatusCoupon, statuses, () -> applyFilters(true)); } + /** + * Configures the discount type filter spinner. + */ private void setupTypeFilter() { String[] types = {"All Types", "FIXED", "PERCENT"}; SpinnerUtils.setupStringFilterSpinner(requireContext(), binding.spinnerTypeCoupon, types, () -> applyFilters(true)); } + /** + * Sets up the search input listener. + */ private void setupSearch() { UIUtils.attachSearch(binding.etSearchCoupon, () -> applyFilters(true)); } + /** + * Configures the swipe-to-refresh layout. + */ private void setupSwipeRefresh() { binding.swipeRefreshCoupon.setOnRefreshListener(() -> applyFilters(true)); } + /** + * Applies filters and loads the coupon list. + */ private void applyFilters(boolean reset) { String statusStr = binding.spinnerStatusCoupon.getSelectedItem() != null ? binding.spinnerStatusCoupon.getSelectedItem().toString() : "All Statuses"; @@ -125,22 +152,34 @@ public class CouponFragment extends Fragment implements CouponAdapter.OnCouponCl viewModel.loadCoupons(reset, active, discountType, null); } + /** + * Navigates to the coupon detail screen. + */ private void openDetail(long id) { Bundle args = new Bundle(); args.putLong("couponId", id); Navigation.findNavController(requireView()).navigate(R.id.couponDetailFragment, args); } + /** + * Handles coupon item clicks by opening details. + */ @Override public void onCouponClick(CouponDTO coupon) { openDetail(coupon.getCouponId()); } + /** + * Shows or hides the bulk delete button based on selection count. + */ @Override public void onSelectionChanged(int count) { binding.btnBulkDeleteCoupons.setVisibility(count > 0 ? View.VISIBLE : View.GONE); } + /** + * Displays a confirmation dialog for deleting multiple coupons. + */ private void confirmBulkDelete() { new AlertDialog.Builder(requireContext()) .setTitle("Confirm Bulk Delete") diff --git a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/CustomerFragment.java b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/CustomerFragment.java index 5afe4d1f..87155463 100644 --- a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/CustomerFragment.java +++ b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/CustomerFragment.java @@ -22,6 +22,9 @@ import java.util.*; import javax.inject.Inject; import javax.inject.Named; +/** + * Fragment for displaying and managing a list of customers. + */ @AndroidEntryPoint public class CustomerFragment extends Fragment implements CustomerAdapter.OnCustomerClickListener { @@ -33,6 +36,9 @@ public class CustomerFragment extends Fragment implements CustomerAdapter.OnCust @Inject @Named("baseUrl") String baseUrl; @Inject TokenManager tokenManager; + /** + * Inflates the layout, initializes ViewModel, and sets up UI components and filters. + */ @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -56,6 +62,9 @@ public class CustomerFragment extends Fragment implements CustomerAdapter.OnCust return binding.getRoot(); } + /** + * Observes the ViewModel for customer list updates and loading status. + */ private void observeViewModel() { viewModel.getFilteredCustomers().observe(getViewLifecycleOwner(), list -> { customerList.clear(); @@ -68,6 +77,9 @@ public class CustomerFragment extends Fragment implements CustomerAdapter.OnCust }); } + /** + * Configures the RecyclerView and its scroll listener for pagination. + */ private void setupRecyclerView() { adapter = new CustomerAdapter(customerList, this); adapter.setBaseUrl(baseUrl); @@ -92,15 +104,24 @@ public class CustomerFragment extends Fragment implements CustomerAdapter.OnCust }); } + /** + * Configures the status filter spinner. + */ private void setupStatusFilter() { String[] statuses = {"All Statuses", "Active", "Inactive"}; SpinnerUtils.setupStringFilterSpinner(requireContext(), binding.spinnerStatusCustomer, statuses, this::applyFilters); } + /** + * Sets up the search input listener. + */ private void setupSearch() { UIUtils.attachSearch(binding.etSearchCustomer, this::applyFilters); } + /** + * Applies filters and triggers data reloading or filtering in ViewModel. + */ private void applyFilters() { String query = binding.etSearchCustomer.getText().toString().trim(); String status = binding.spinnerStatusCustomer.getSelectedItem() != null ? @@ -108,10 +129,16 @@ public class CustomerFragment extends Fragment implements CustomerAdapter.OnCust viewModel.filter(query, status); } + /** + * Configures the swipe-to-refresh layout. + */ private void setupSwipeRefresh() { binding.swipeRefreshCustomer.setOnRefreshListener(() -> viewModel.loadCustomers(true)); } + /** + * Navigates to the customer detail screen. + */ private void openDetail(int position) { Bundle args = new Bundle(); if (position != -1) { @@ -129,11 +156,17 @@ public class CustomerFragment extends Fragment implements CustomerAdapter.OnCust NavHostFragment.findNavController(this).navigate(R.id.nav_customer_detail, args); } + /** + * Handles customer item clicks by opening details. + */ @Override public void onCustomerClick(int position) { openDetail(position); } + /** + * Cleans up the binding reference. + */ @Override public void onDestroyView() { super.onDestroyView(); diff --git a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/InventoryFragment.java b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/InventoryFragment.java index 4e2c2337..c01fb710 100644 --- a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/InventoryFragment.java +++ b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/InventoryFragment.java @@ -32,6 +32,9 @@ import javax.inject.Inject; import dagger.hilt.android.AndroidEntryPoint; +/** + * Fragment for displaying and managing inventory items. + */ @AndroidEntryPoint public class InventoryFragment extends Fragment implements InventoryAdapter.OnInventoryClickListener { @@ -43,12 +46,18 @@ public class InventoryFragment extends Fragment implements InventoryAdapter.OnIn @Inject TokenManager tokenManager; + /** + * Initializes the ViewModel. + */ @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); viewModel = new ViewModelProvider(this).get(InventoryListViewModel.class); } + /** + * Inflates the layout and sets up UI components, filters, and observers. + */ @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -71,6 +80,9 @@ public class InventoryFragment extends Fragment implements InventoryAdapter.OnIn return binding.getRoot(); } + /** + * Observes the ViewModel for inventory list updates, store list, and loading status. + */ private void observeViewModel() { viewModel.getInventory().observe(getViewLifecycleOwner(), list -> { inventoryList.clear(); @@ -88,6 +100,9 @@ public class InventoryFragment extends Fragment implements InventoryAdapter.OnIn }); } + /** + * Configures the bulk delete handler for multiple inventory item deletion. + */ private void setupBulkDelete() { bulkDeleteHandler = new BulkDeleteHandler( this, @@ -101,18 +116,27 @@ public class InventoryFragment extends Fragment implements InventoryAdapter.OnIn ); } + /** + * Reloads store data if necessary when the fragment resumes. + */ @Override public void onResume() { super.onResume(); if (!isStaff()) viewModel.loadStores(); } + /** + * Cleans up the binding reference. + */ @Override public void onDestroyView() { super.onDestroyView(); binding = null; } + /** + * Sets up the filter visibility toggle, considering user roles. + */ private void setupFilterToggle() { if (isStaff()) { UIUtils.setupFilterToggle(binding.btnToggleFilter, binding.layoutFilter, binding.etSearchInventory); @@ -122,18 +146,30 @@ public class InventoryFragment extends Fragment implements InventoryAdapter.OnIn } } + /** + * Checks if the currently logged-in user has the STAFF role. + */ private boolean isStaff() { return "STAFF".equalsIgnoreCase(tokenManager.getRole()); } + /** + * Sets up the search input listener. + */ private void setupSearch() { UIUtils.attachSearch(binding.etSearchInventory, () -> loadInventory(true)); } + /** + * Configures the store filter spinner. + */ private void setupStoreFilter() { SpinnerUtils.setupFilterSpinner(binding.spinnerStore, () -> loadInventory(true)); } + /** + * Configures the RecyclerView and its scroll listener for pagination. + */ private void setupRecyclerView() { adapter = new InventoryAdapter(inventoryList, this); binding.recyclerViewInventory.setLayoutManager(new LinearLayoutManager(getContext())); @@ -156,10 +192,16 @@ public class InventoryFragment extends Fragment implements InventoryAdapter.OnIn }); } + /** + * Configures the swipe-to-refresh layout. + */ private void setupSwipeRefresh() { binding.swipeRefreshInventory.setOnRefreshListener(() -> loadInventory(true)); } + /** + * Loads inventory data based on current search query and store filter. + */ private void loadInventory(boolean reset) { String query = binding.etSearchInventory != null ? binding.etSearchInventory.getText().toString().trim() : ""; if (query.isEmpty()) query = null; @@ -178,6 +220,9 @@ public class InventoryFragment extends Fragment implements InventoryAdapter.OnIn viewModel.loadInventory(reset, query, storeId); } + /** + * Navigates to the inventory detail screen. + */ private void openDetail(InventoryDTO inv) { Bundle args = new Bundle(); if (inv != null) { @@ -186,6 +231,9 @@ public class InventoryFragment extends Fragment implements InventoryAdapter.OnIn NavHostFragment.findNavController(this).navigate(R.id.nav_inventory_detail, args); } + /** + * Handles inventory item clicks by opening details. + */ @Override public void onInventoryClick(int position) { if (position >= 0 && position < inventoryList.size()) { @@ -193,6 +241,9 @@ public class InventoryFragment extends Fragment implements InventoryAdapter.OnIn } } + /** + * Forwards selection changes to the bulk delete handler. + */ @Override public void onSelectionChanged(int selectedCount) { if (bulkDeleteHandler != null) { diff --git a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/PetFragment.java b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/PetFragment.java index 96225e6a..c7139548 100644 --- a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/PetFragment.java +++ b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/PetFragment.java @@ -33,6 +33,9 @@ import javax.inject.Named; import dagger.hilt.android.AndroidEntryPoint; +/** + * Fragment for displaying and managing a list of pets. + */ @AndroidEntryPoint public class PetFragment extends Fragment implements PetAdapter.OnPetClickListener { private FragmentPetBinding binding; @@ -44,12 +47,18 @@ public class PetFragment extends Fragment implements PetAdapter.OnPetClickListen @Inject @Named("baseUrl") String baseUrl; @Inject TokenManager tokenManager; + /** + * Initializes the view model. + */ @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); viewModel = new ViewModelProvider(this).get(PetListViewModel.class); } + /** + * Inflates the layout and initializes UI components and filters. + */ @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -72,6 +81,9 @@ public class PetFragment extends Fragment implements PetAdapter.OnPetClickListen return binding.getRoot(); } + /** + * Observes LiveData from the ViewModel to update the list and filter options. + */ private void observeViewModel() { viewModel.getPets().observe(getViewLifecycleOwner(), list -> { petList.clear(); @@ -94,6 +106,9 @@ public class PetFragment extends Fragment implements PetAdapter.OnPetClickListen }); } + /** + * Configures the handler for bulk deletion of pets. + */ private void setupBulkDelete() { bulkDeleteHandler = new BulkDeleteHandler( this, @@ -107,6 +122,9 @@ public class PetFragment extends Fragment implements PetAdapter.OnPetClickListen ); } + /** + * Refreshes pet data and filters when the fragment is resumed. + */ @Override public void onResume() { super.onResume(); @@ -115,6 +133,9 @@ public class PetFragment extends Fragment implements PetAdapter.OnPetClickListen if (!isStaff()) viewModel.loadStores(); } + /** + * Sets up the visibility of filters based on the user's role. + */ private void setupFilterToggle() { if (isStaff()) { UIUtils.setupFilterToggle(binding.btnToggleFilter, binding.layoutFilter, binding.etSearchPet, @@ -126,32 +147,53 @@ public class PetFragment extends Fragment implements PetAdapter.OnPetClickListen } } + /** + * Checks if the current user has the 'STAFF' role. + */ private boolean isStaff() { return "STAFF".equalsIgnoreCase(tokenManager.getRole()); } + /** + * Attaches search functionality to the search input field. + */ private void setupSearch() { UIUtils.attachSearch(binding.etSearchPet, () -> loadPetData(true)); } + /** + * Initializes the status filter spinner. + */ private void setupStatusFilter() { String[] statuses = {"All Statuses", "Available", "Adopted", "Owned", "Pending"}; SpinnerUtils.setupStringFilterSpinner(requireContext(), binding.spinnerStatus, statuses, () -> loadPetData(true)); } + /** + * Initializes the species filter spinner. + */ private void setupSpeciesFilter() { String[] initial = {"All Species"}; SpinnerUtils.setupStringFilterSpinner(requireContext(), binding.spinnerSpecies, initial, () -> loadPetData(true)); } + /** + * Initializes the store filter spinner. + */ private void setupStoreFilter() { SpinnerUtils.setupFilterSpinner(binding.spinnerStore, () -> loadPetData(true)); } + /** + * Configures the swipe-to-refresh layout. + */ private void setupSwipeRefresh() { binding.swipeRefreshPet.setOnRefreshListener(() -> loadPetData(true)); } + /** + * Triggers loading of pet data from the backend with current filters. + */ private void loadPetData(boolean reset) { String query = binding.etSearchPet.getText().toString().trim(); String status = binding.spinnerStatus.getSelectedItem() != null ? binding.spinnerStatus.getSelectedItem().toString() : "All Statuses"; @@ -171,6 +213,9 @@ public class PetFragment extends Fragment implements PetAdapter.OnPetClickListen viewModel.loadPets(reset, query, status, species, storeId); } + /** + * Configures the RecyclerView and its scroll listener for pagination. + */ private void setupRecyclerView() { adapter = new PetAdapter(petList, this); adapter.setBaseUrl(baseUrl); @@ -195,6 +240,9 @@ public class PetFragment extends Fragment implements PetAdapter.OnPetClickListen }); } + /** + * Navigates to the profile view of a specific pet. + */ private void openPetProfile(int position) { Bundle args = new Bundle(); PetDTO pet = petList.get(position); @@ -202,15 +250,24 @@ public class PetFragment extends Fragment implements PetAdapter.OnPetClickListen NavHostFragment.findNavController(this).navigate(R.id.nav_pet_profile, args); } + /** + * Navigates to the screen for adding a new pet. + */ private void openPetDetails() { NavHostFragment.findNavController(this).navigate(R.id.nav_pet_detail); } + /** + * Handles clicks on individual pets in the list. + */ @Override public void onPetClick(int position) { openPetProfile(position); } + /** + * Notifies the bulk delete handler when item selection changes. + */ @Override public void onSelectionChanged(int selectedCount) { if (bulkDeleteHandler != null) { @@ -218,6 +275,9 @@ public class PetFragment extends Fragment implements PetAdapter.OnPetClickListen } } + /** + * Cleans up the binding when the view is destroyed. + */ @Override public void onDestroyView() { super.onDestroyView(); diff --git a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/ProductFragment.java b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/ProductFragment.java index 0820aca6..34d30e6a 100644 --- a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/ProductFragment.java +++ b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/ProductFragment.java @@ -31,6 +31,9 @@ import javax.inject.Named; import dagger.hilt.android.AndroidEntryPoint; +/** + * Fragment for displaying and managing a list of products. + */ @AndroidEntryPoint public class ProductFragment extends Fragment implements ProductAdapter.OnProductClickListener { @@ -41,12 +44,18 @@ public class ProductFragment extends Fragment implements ProductAdapter.OnProduc @Inject @Named("baseUrl") String baseUrl; + /** + * Initializes the ViewModel. + */ @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); viewModel = new ViewModelProvider(this).get(ProductListViewModel.class); } + /** + * Inflates the layout and sets up UI components. + */ @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -66,6 +75,9 @@ public class ProductFragment extends Fragment implements ProductAdapter.OnProduc return binding.getRoot(); } + /** + * Observes the ViewModel for product list, categories, and loading status. + */ private void observeViewModel() { viewModel.getProducts().observe(getViewLifecycleOwner(), list -> { productList.clear(); @@ -83,6 +95,9 @@ public class ProductFragment extends Fragment implements ProductAdapter.OnProduc }); } + /** + * Reloads product data and categories when the fragment resumes. + */ @Override public void onResume() { super.onResume(); @@ -90,23 +105,38 @@ public class ProductFragment extends Fragment implements ProductAdapter.OnProduc viewModel.loadCategories(); } + /** + * Sets up the filter visibility toggle. + */ private void setupFilterToggle() { UIUtils.setupFilterToggle(binding.btnToggleFilter, binding.layoutFilter, binding.etSearchProduct, binding.spinnerCategory); } + /** + * Sets up the search input listener. + */ private void setupSearch() { UIUtils.attachSearch(binding.etSearchProduct, () -> loadProductData(true)); } + /** + * Configures the category filter spinner. + */ private void setupCategoryFilter() { SpinnerUtils.setupFilterSpinner(binding.spinnerCategory, () -> loadProductData(true)); } + /** + * Configures the swipe-to-refresh layout. + */ private void setupSwipeRefresh() { binding.swipeRefreshProduct.setOnRefreshListener(() -> loadProductData(true)); } + /** + * Loads product data based on current filters and search query. + */ private void loadProductData(boolean reset) { String query = binding.etSearchProduct.getText().toString().trim(); if (query.isEmpty()) query = null; @@ -120,6 +150,9 @@ public class ProductFragment extends Fragment implements ProductAdapter.OnProduc viewModel.loadProducts(reset, query, categoryId); } + /** + * Configures the RecyclerView and its scroll listener for pagination. + */ private void setupRecyclerView() { adapter = new ProductAdapter(productList, this); adapter.setBaseUrl(baseUrl); @@ -143,6 +176,9 @@ public class ProductFragment extends Fragment implements ProductAdapter.OnProduc }); } + /** + * Navigates to the product detail screen. + */ private void openProductDetails(int position) { Bundle args = new Bundle(); if (position != -1) { @@ -152,11 +188,17 @@ public class ProductFragment extends Fragment implements ProductAdapter.OnProduc NavHostFragment.findNavController(this).navigate(R.id.nav_product_detail, args); } + /** + * Handles product item clicks by opening details. + */ @Override public void onProductClick(int position) { openProductDetails(position); } + /** + * Cleans up the binding reference. + */ @Override public void onDestroyView() { super.onDestroyView(); diff --git a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/ProductSupplierFragment.java b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/ProductSupplierFragment.java index c4751ae3..d3b63523 100644 --- a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/ProductSupplierFragment.java +++ b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/ProductSupplierFragment.java @@ -29,6 +29,9 @@ import java.util.List; import dagger.hilt.android.AndroidEntryPoint; +/** + * Fragment for displaying and managing the relationships between products and suppliers. + */ @AndroidEntryPoint public class ProductSupplierFragment extends Fragment implements ProductSupplierAdapter.OnProductSupplierClickListener { @@ -40,12 +43,18 @@ public class ProductSupplierFragment extends Fragment private ProductSupplierListViewModel viewModel; private BulkDeleteHandler bulkDeleteHandler; + /** + * Initializes the ViewModel. + */ @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); viewModel = new ViewModelProvider(this).get(ProductSupplierListViewModel.class); } + /** + * Inflates the layout and sets up UI components, filters, and observers. + */ @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -67,6 +76,9 @@ public class ProductSupplierFragment extends Fragment return binding.getRoot(); } + /** + * Observes the ViewModel for product-supplier list, products, suppliers, and loading status. + */ private void observeViewModel() { viewModel.getProductSuppliers().observe(getViewLifecycleOwner(), list -> { psList.clear(); @@ -89,6 +101,9 @@ public class ProductSupplierFragment extends Fragment }); } + /** + * Configures the bulk delete handler for multiple product-supplier relationship deletion. + */ private void setupBulkDelete() { bulkDeleteHandler = new BulkDeleteHandler( this, @@ -102,6 +117,9 @@ public class ProductSupplierFragment extends Fragment ); } + /** + * Reloads data and filter options when the fragment resumes. + */ @Override public void onResume() { super.onResume(); @@ -109,17 +127,26 @@ public class ProductSupplierFragment extends Fragment viewModel.loadFilterData(); } + /** + * Cleans up the binding reference. + */ @Override public void onDestroyView() { super.onDestroyView(); binding = null; } + /** + * Sets up the filter visibility toggle. + */ private void setupFilterToggle() { UIUtils.setupFilterToggle(binding.btnToggleFilter, binding.layoutFilter, binding.etSearchPS, binding.spinnerProduct, binding.spinnerSupplier); } + /** + * Configures the RecyclerView and its scroll listener for pagination. + */ private void setupRecyclerView() { adapter = new ProductSupplierAdapter(psList, this); binding.recyclerViewPS.setLayoutManager(new LinearLayoutManager(getContext())); @@ -142,22 +169,37 @@ public class ProductSupplierFragment extends Fragment }); } + /** + * Sets up the search input listener. + */ private void setupSearch() { UIUtils.attachSearch(binding.etSearchPS, () -> loadData(true)); } + /** + * Configures the product filter spinner. + */ private void setupProductFilter() { SpinnerUtils.setupFilterSpinner(binding.spinnerProduct, () -> loadData(true)); } + /** + * Configures the supplier filter spinner. + */ private void setupSupplierFilter() { SpinnerUtils.setupFilterSpinner(binding.spinnerSupplier, () -> loadData(true)); } + /** + * Configures the swipe-to-refresh layout. + */ private void setupSwipeRefresh() { binding.swipeRefreshPS.setOnRefreshListener(() -> loadData(true)); } + /** + * Loads product-supplier data based on current search query and filters. + */ private void loadData(boolean reset) { String query = binding.etSearchPS.getText().toString().trim(); if (query.isEmpty()) query = null; @@ -177,6 +219,9 @@ public class ProductSupplierFragment extends Fragment viewModel.loadProductSuppliers(reset, query, productId, supplierId); } + /** + * Navigates to the product-supplier detail screen. + */ private void openDetail(int position) { Bundle args = new Bundle(); if (position != -1) { @@ -187,9 +232,15 @@ public class ProductSupplierFragment extends Fragment NavHostFragment.findNavController(this).navigate(R.id.nav_product_supplier_detail, args); } + /** + * Handles product-supplier item clicks by opening details. + */ @Override public void onProductSupplierClick(int position) { openDetail(position); } + /** + * Forwards selection changes to the bulk delete handler. + */ @Override public void onSelectionChanged(int count) { if (bulkDeleteHandler != null) { diff --git a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/PurchaseOrderFragment.java b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/PurchaseOrderFragment.java index f4e4e230..ea4a2bbd 100644 --- a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/PurchaseOrderFragment.java +++ b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/PurchaseOrderFragment.java @@ -30,6 +30,9 @@ import javax.inject.Inject; import dagger.hilt.android.AndroidEntryPoint; +/** + * Fragment for displaying and managing a list of purchase orders. + */ @AndroidEntryPoint public class PurchaseOrderFragment extends Fragment implements PurchaseOrderAdapter.OnPurchaseOrderClickListener { @@ -41,12 +44,18 @@ public class PurchaseOrderFragment extends Fragment @Inject TokenManager tokenManager; + /** + * Initializes the ViewModel. + */ @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); viewModel = new ViewModelProvider(this).get(PurchaseOrderListViewModel.class); } + /** + * Inflates the layout and sets up UI components, filters, and observers. + */ @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -64,6 +73,9 @@ public class PurchaseOrderFragment extends Fragment return binding.getRoot(); } + /** + * Observes the ViewModel for purchase order list, stores, and loading status. + */ private void observeViewModel() { viewModel.getPurchaseOrders().observe(getViewLifecycleOwner(), list -> { poList.clear(); @@ -81,6 +93,9 @@ public class PurchaseOrderFragment extends Fragment }); } + /** + * Reloads data and stores if necessary when the fragment resumes. + */ @Override public void onResume() { super.onResume(); @@ -88,6 +103,9 @@ public class PurchaseOrderFragment extends Fragment if (!isStaff()) viewModel.loadStores(); } + /** + * Sets up the filter visibility toggle + */ private void setupFilterToggle() { if (isStaff()) { UIUtils.setupFilterToggle(binding.btnToggleFilter, binding.layoutFilter, binding.etSearchPO); @@ -97,18 +115,30 @@ public class PurchaseOrderFragment extends Fragment } } + /** + * Checks if the currently logged-in user has the STAFF role. + */ private boolean isStaff() { return "STAFF".equalsIgnoreCase(tokenManager.getRole()); } + /** + * Sets up the search input listener. + */ private void setupSearch() { UIUtils.attachSearch(binding.etSearchPO, () -> loadData(true)); } + /** + * Configures the store filter spinner. + */ private void setupStoreFilter() { SpinnerUtils.setupFilterSpinner(binding.spinnerStore, () -> loadData(true)); } + /** + * Configures the RecyclerView and its scroll listener for pagination. + */ private void setupRecyclerView() { adapter = new PurchaseOrderAdapter(poList, this); binding.recyclerViewPO.setLayoutManager(new LinearLayoutManager(getContext())); @@ -131,10 +161,16 @@ public class PurchaseOrderFragment extends Fragment }); } + /** + * Configures the swipe-to-refresh layout. + */ private void setupSwipeRefresh() { binding.swipeRefreshPO.setOnRefreshListener(() -> loadData(true)); } + /** + * Loads purchase order data based on current search query and store filter. + */ private void loadData(boolean reset) { String query = binding.etSearchPO != null ? binding.etSearchPO.getText().toString().trim() : ""; if (query.isEmpty()) query = null; @@ -153,6 +189,9 @@ public class PurchaseOrderFragment extends Fragment viewModel.loadPurchaseOrders(reset, query, storeId); } + /** + * Navigates to the purchase order detail screen. + */ private void openDetail(int position) { Bundle args = new Bundle(); PurchaseOrderDTO po = poList.get(position); @@ -160,11 +199,17 @@ public class PurchaseOrderFragment extends Fragment NavHostFragment.findNavController(this).navigate(R.id.nav_purchase_order_detail, args); } + /** + * Handles purchase order item clicks by opening details. + */ @Override public void onPurchaseOrderClick(int position) { openDetail(position); } + /** + * Cleans up the binding reference. + */ @Override public void onDestroyView() { super.onDestroyView(); diff --git a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/SaleFragment.java b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/SaleFragment.java index f6d0c388..890f8c68 100644 --- a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/SaleFragment.java +++ b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/SaleFragment.java @@ -31,6 +31,9 @@ import javax.inject.Inject; import dagger.hilt.android.AndroidEntryPoint; +/** + * Fragment for displaying and managing a list of sales. + */ @AndroidEntryPoint public class SaleFragment extends Fragment implements SaleAdapter.OnSaleClickListener { @@ -41,6 +44,9 @@ public class SaleFragment extends Fragment implements SaleAdapter.OnSaleClickLis @Inject TokenManager tokenManager; + /** + * Inflates the layout for this fragment. + */ @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -48,6 +54,9 @@ public class SaleFragment extends Fragment implements SaleAdapter.OnSaleClickLis return binding.getRoot(); } + /** + * Initializes UI components and observers after the view is created. + */ @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); @@ -79,6 +88,9 @@ public class SaleFragment extends Fragment implements SaleAdapter.OnSaleClickLis NavHostFragment.findNavController(this).navigate(R.id.nav_refund)); } + /** + * Observes LiveData from the ViewModel to update the list and filter options. + */ private void observeViewModel() { viewModel.getSales().observe(getViewLifecycleOwner(), list -> { saleList.clear(); @@ -101,6 +113,9 @@ public class SaleFragment extends Fragment implements SaleAdapter.OnSaleClickLis }); } + /** + * Refreshes lookup data when the fragment is resumed. + */ @Override public void onResume() { super.onResume(); @@ -108,6 +123,9 @@ public class SaleFragment extends Fragment implements SaleAdapter.OnSaleClickLis viewModel.loadCustomers(); } + /** + * Sets up the visibility of filters. + */ private void setupFilterToggle() { if (isStaff()) { UIUtils.setupFilterToggle(binding.btnToggleFilter, binding.layoutFilter, binding.etSearchSale, @@ -119,32 +137,53 @@ public class SaleFragment extends Fragment implements SaleAdapter.OnSaleClickLis } } + /** + * Checks if the current user has the 'STAFF' role. + */ private boolean isStaff() { return "STAFF".equalsIgnoreCase(tokenManager.getRole()); } + /** + * Checks if the current user has the 'ADMIN' role. + */ private boolean isAdmin() { return "ADMIN".equalsIgnoreCase(tokenManager.getRole()); } + /** + * Initializes the store filter spinner. + */ private void setupStoreFilter() { SpinnerUtils.setupFilterSpinner(binding.spinnerStore, () -> loadSales(true)); } + /** + * Initializes the payment method filter spinner. + */ private void setupPaymentMethodFilter() { String[] paymentMethods = {"All Payments", "Cash", "Card"}; SpinnerUtils.setupStringFilterSpinner(requireContext(), binding.spinnerPaymentMethod, paymentMethods, () -> loadSales(true)); } + /** + * Initializes the refund status filter spinner. + */ private void setupRefundStatusFilter() { String[] refundStatuses = {"All Status", "Sale", "Refund"}; SpinnerUtils.setupStringFilterSpinner(requireContext(), binding.spinnerRefundStatus, refundStatuses, () -> loadSales(true)); } + /** + * Initializes the customer filter spinner. + */ private void setupCustomerFilter() { SpinnerUtils.setupFilterSpinner(binding.spinnerCustomer, () -> loadSales(true)); } + /** + * Configures the RecyclerView and its scroll listener for pagination. + */ private void setupRecyclerView() { adapter = new SaleAdapter(saleList, this); binding.recyclerViewSales.setLayoutManager(new LinearLayoutManager(getContext())); @@ -168,14 +207,23 @@ public class SaleFragment extends Fragment implements SaleAdapter.OnSaleClickLis }); } + /** + * Attaches search functionality to the search input field. + */ private void setupSearch() { UIUtils.attachSearch(binding.etSearchSale, () -> loadSales(true)); } + /** + * Configures the swipe-to-refresh layout. + */ private void setupSwipeRefresh() { binding.swipeRefreshSale.setOnRefreshListener(() -> loadSales(true)); } + /** + * Triggers loading of sale data from the backend with current filters. + */ private void loadSales(boolean reset) { String query = binding.etSearchSale != null ? binding.etSearchSale.getText().toString().trim() : ""; if (query.isEmpty()) query = null; @@ -210,6 +258,9 @@ public class SaleFragment extends Fragment implements SaleAdapter.OnSaleClickLis viewModel.loadSales(reset, query, paymentMethod, storeId, isRefund, customerId); } + /** + * Handles clicks on individual sales in the list. + */ @Override public void onSaleClick(int position) { if (position < 0 || position >= saleList.size()) return; @@ -225,6 +276,9 @@ public class SaleFragment extends Fragment implements SaleAdapter.OnSaleClickLis NavHostFragment.findNavController(this).navigate(R.id.nav_sale_detail, args); } + /** + * Cleans up the binding when the view is destroyed. + */ @Override public void onDestroyView() { super.onDestroyView(); diff --git a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/ServiceFragment.java b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/ServiceFragment.java index 1aaf625d..d5a73312 100644 --- a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/ServiceFragment.java +++ b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/ServiceFragment.java @@ -39,12 +39,18 @@ public class ServiceFragment extends Fragment implements ServiceAdapter.OnServic private ServiceListViewModel viewModel; private BulkDeleteHandler bulkDeleteHandler; + /** + * Initializes the ViewModel. + */ @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); viewModel = new ViewModelProvider(this).get(ServiceListViewModel.class); } + /** + * Inflates the layout and sets up UI components and observers. + */ @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -67,6 +73,9 @@ public class ServiceFragment extends Fragment implements ServiceAdapter.OnServic return binding.getRoot(); } + /** + * Observes the ViewModel for service list updates and loading status. + */ private void observeViewModel() { viewModel.getServices().observe(getViewLifecycleOwner(), list -> { serviceList.clear(); @@ -79,6 +88,9 @@ public class ServiceFragment extends Fragment implements ServiceAdapter.OnServic }); } + /** + * Configures the bulk delete handler for multiple service deletion. + */ private void setupBulkDelete() { bulkDeleteHandler = new BulkDeleteHandler( this, @@ -92,20 +104,32 @@ public class ServiceFragment extends Fragment implements ServiceAdapter.OnServic ); } + /** + * Cleans up the binding reference. + */ @Override public void onDestroyView() { super.onDestroyView(); binding = null; } + /** + * Sets up the filter visibility toggle. + */ private void setupFilterToggle() { UIUtils.setupFilterToggle(binding.btnToggleFilter, binding.layoutFilter, binding.etSearchService); } + /** + * Sets up the search input listener. + */ private void setupSearch() { UIUtils.attachSearch(binding.etSearchService, () -> loadServices(true)); } + /** + * Configures the RecyclerView and its scroll listener for pagination. + */ private void setupRecyclerView() { adapter = new ServiceAdapter(serviceList, this); binding.recyclerViewServices.setLayoutManager(new LinearLayoutManager(getContext())); @@ -128,16 +152,25 @@ public class ServiceFragment extends Fragment implements ServiceAdapter.OnServic }); } + /** + * Configures the swipe-to-refresh layout. + */ private void setupSwipeRefresh() { binding.swipeRefreshService.setOnRefreshListener(() -> loadServices(true)); } + /** + * Loads service data based on current filters and search query. + */ private void loadServices(boolean reset) { String query = binding.etSearchService.getText().toString().trim(); if (query.isEmpty()) query = null; viewModel.loadServices(reset, query); } + /** + * Navigates to the service detail screen. + */ private void openDetail(ServiceDTO service) { Bundle args = new Bundle(); if (service != null) { @@ -146,6 +179,9 @@ public class ServiceFragment extends Fragment implements ServiceAdapter.OnServic NavHostFragment.findNavController(this).navigate(R.id.nav_service_detail, args); } + /** + * Handles service item clicks by opening details. + */ @Override public void onServiceClick(int position) { if (position >= 0 && position < serviceList.size()) { @@ -153,6 +189,9 @@ public class ServiceFragment extends Fragment implements ServiceAdapter.OnServic } } + /** + * Forwards selection changes to the bulk delete handler. + */ @Override public void onSelectionChanged(int count) { if (bulkDeleteHandler != null) { diff --git a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/StaffFragment.java b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/StaffFragment.java index e1e92ca7..81efdd4a 100644 --- a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/StaffFragment.java +++ b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/StaffFragment.java @@ -24,6 +24,9 @@ import java.util.*; import javax.inject.Inject; import javax.inject.Named; +/** + * Fragment for displaying and managing a list of staff members. + */ @AndroidEntryPoint public class StaffFragment extends Fragment implements EmployeeAdapter.OnEmployeeClickListener { @@ -35,6 +38,9 @@ public class StaffFragment extends Fragment implements EmployeeAdapter.OnEmploye @Inject @Named("baseUrl") String baseUrl; @Inject TokenManager tokenManager; + /** + * Inflates the layout and initializes UI components, filters, and observers. + */ @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -60,6 +66,9 @@ public class StaffFragment extends Fragment implements EmployeeAdapter.OnEmploye return binding.getRoot(); } + /** + * Observes LiveData from the ViewModel to update the list and filter options. + */ private void observeViewModel() { viewModel.getFilteredEmployees().observe(getViewLifecycleOwner(), list -> { staffList.clear(); @@ -77,6 +86,9 @@ public class StaffFragment extends Fragment implements EmployeeAdapter.OnEmploye }); } + /** + * Configures the RecyclerView and its scroll listener for pagination. + */ private void setupRecyclerView() { adapter = new EmployeeAdapter(staffList, this); adapter.setBaseUrl(baseUrl); @@ -101,19 +113,31 @@ public class StaffFragment extends Fragment implements EmployeeAdapter.OnEmploye }); } + /** + * Initializes the status filter spinner. + */ private void setupStatusFilter() { String[] statuses = {"All Statuses", "Active", "Inactive"}; SpinnerUtils.setupStringFilterSpinner(requireContext(), binding.spinnerStatusStaff, statuses, this::applyFilters); } + /** + * Initializes the store filter spinner. + */ private void setupStoreFilter() { SpinnerUtils.setupFilterSpinner(binding.spinnerStoreStaff, this::applyFilters); } + /** + * Attaches search functionality to the search input field. + */ private void setupSearch() { UIUtils.attachSearch(binding.etSearchStaff, this::applyFilters); } + /** + * Applies the selected filters and triggers a data reload from the view model. + */ private void applyFilters() { String query = binding.etSearchStaff.getText().toString().trim(); String status = binding.spinnerStatusStaff.getSelectedItem() != null ? @@ -128,10 +152,16 @@ public class StaffFragment extends Fragment implements EmployeeAdapter.OnEmploye viewModel.filter(query, storeId, status); } + /** + * Configures the swipe-to-refresh layout. + */ private void setupSwipeRefresh() { binding.swipeRefreshStaff.setOnRefreshListener(() -> viewModel.loadStaff(true)); } + /** + * Navigates to the staff detail screen for adding or editing an employee. + */ private void openDetail(int position) { Bundle args = new Bundle(); if (position != -1) { @@ -149,11 +179,17 @@ public class StaffFragment extends Fragment implements EmployeeAdapter.OnEmploye NavHostFragment.findNavController(this).navigate(R.id.nav_staff_detail, args); } + /** + * Handles clicks on individual staff members in the list. + */ @Override public void onEmployeeClick(int position) { openDetail(position); } + /** + * Cleans up the binding when the view is destroyed. + */ @Override public void onDestroyView() { super.onDestroyView(); diff --git a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/SupplierFragment.java b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/SupplierFragment.java index 163ac217..ca10c7d0 100644 --- a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/SupplierFragment.java +++ b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/SupplierFragment.java @@ -27,6 +27,9 @@ import java.util.List; import dagger.hilt.android.AndroidEntryPoint; +/** + * Fragment for displaying and managing a list of suppliers. + */ @AndroidEntryPoint public class SupplierFragment extends Fragment implements SupplierAdapter.OnSupplierClickListener { @@ -36,12 +39,18 @@ public class SupplierFragment extends Fragment implements SupplierAdapter.OnSupp private SupplierListViewModel viewModel; private BulkDeleteHandler bulkDeleteHandler; + /** + * Initializes the ViewModel. + */ @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); viewModel = new ViewModelProvider(this).get(SupplierListViewModel.class); } + /** + * Inflates the layout and sets up UI components, bulk delete, and observers. + */ @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -63,6 +72,9 @@ public class SupplierFragment extends Fragment implements SupplierAdapter.OnSupp return binding.getRoot(); } + /** + * Observes the ViewModel for supplier list updates and loading status. + */ private void observeViewModel() { viewModel.getSuppliers().observe(getViewLifecycleOwner(), list -> { supplierList.clear(); @@ -75,6 +87,9 @@ public class SupplierFragment extends Fragment implements SupplierAdapter.OnSupp }); } + /** + * Configures the bulk delete handler for multiple supplier deletion. + */ private void setupBulkDelete() { bulkDeleteHandler = new BulkDeleteHandler( this, @@ -88,24 +103,39 @@ public class SupplierFragment extends Fragment implements SupplierAdapter.OnSupp ); } + /** + * Cleans up the binding reference. + */ @Override public void onDestroyView() { super.onDestroyView(); binding = null; } + /** + * Sets up the filter visibility toggle. + */ private void setupFilterToggle() { UIUtils.setupFilterToggle(binding.btnToggleFilter, binding.layoutFilter, binding.etSearchSupplier); } + /** + * Sets up the search input listener. + */ private void setupSearch() { UIUtils.attachSearch(binding.etSearchSupplier, () -> loadSupplierData(true)); } + /** + * Configures the swipe-to-refresh layout. + */ private void setupSwipeRefresh() { binding.swipeRefreshSupplier.setOnRefreshListener(() -> loadSupplierData(true)); } + /** + * Navigates to the supplier detail screen. + */ private void openSupplierDetails(int position) { Bundle args = new Bundle(); if (position != -1) { @@ -115,11 +145,17 @@ public class SupplierFragment extends Fragment implements SupplierAdapter.OnSupp NavHostFragment.findNavController(this).navigate(R.id.nav_supplier_detail, args); } + /** + * Handles supplier item clicks by opening details. + */ @Override public void onSupplierClick(int position) { openSupplierDetails(position); } + /** + * Forwards selection changes to the bulk delete handler. + */ @Override public void onSelectionChanged(int count) { if (bulkDeleteHandler != null) { @@ -127,12 +163,18 @@ public class SupplierFragment extends Fragment implements SupplierAdapter.OnSupp } } + /** + * Loads supplier data based on current search query. + */ private void loadSupplierData(boolean reset) { String query = binding.etSearchSupplier != null ? binding.etSearchSupplier.getText().toString().trim() : ""; if (query.isEmpty()) query = null; viewModel.loadSuppliers(reset, query); } + /** + * Configures the RecyclerView and its scroll listener for pagination. + */ private void setupRecyclerView() { adapter = new SupplierAdapter(supplierList, this); binding.recyclerViewSuppliers.setLayoutManager(new LinearLayoutManager(getContext())); diff --git a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/AdoptionDetailFragment.java b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/AdoptionDetailFragment.java index 1cd47561..64ec51d8 100644 --- a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/AdoptionDetailFragment.java +++ b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/AdoptionDetailFragment.java @@ -39,12 +39,18 @@ public class AdoptionDetailFragment extends Fragment { @Inject TokenManager tokenManager; + /** + * Initializes the fragment and its ViewModel. + */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); viewModel = new ViewModelProvider(this).get(AdoptionDetailViewModel.class); } + /** + * Inflates the layout for the fragment + */ @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -52,6 +58,9 @@ public class AdoptionDetailFragment extends Fragment { return binding.getRoot(); } + /** + * Sets up UI components, observers, and loads initial data after the view is created. + */ @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); @@ -68,6 +77,9 @@ public class AdoptionDetailFragment extends Fragment { binding.btnDeleteAdoption.setOnClickListener(v -> confirmDelete()); } + /** + * Sets up observers for ViewModel to update the UI dynamically. + */ private void observeViewModel() { viewModel.getViewState().observe(getViewLifecycleOwner(), this::applyViewState); @@ -113,18 +125,27 @@ public class AdoptionDetailFragment extends Fragment { }); } + /** + * Shows or hides the loading bar. + */ private void setLoading(boolean loading) { if (binding != null) { binding.progressBar.setVisibility(loading ? View.VISIBLE : View.GONE); } } + /** + * Cleans up the binding reference. + */ @Override public void onDestroyView() { super.onDestroyView(); binding = null; } + /** + * Initializes the spinners with data and selection listeners. + */ private void setupSpinners() { SpinnerUtils.setupStringSpinner(requireContext(), binding.spinnerAdoptionStatus, new String[]{}); @@ -141,11 +162,17 @@ public class AdoptionDetailFragment extends Fragment { SpinnerUtils.setOnIndexSelectedListener(binding.spinnerAdoptionStatus, p -> notifyDateStatusChange()); } + /** + * Configures the date picker for the adoption date field. + */ private void setupDatePicker() { binding.etAdoptionDate.setOnClickListener(v -> UIUtils.showDatePicker(requireContext(), binding.etAdoptionDate, this::notifyDateStatusChange)); } + /** + * Notifies the ViewModel when the date or status changes to update available options. + */ private void notifyDateStatusChange() { if (isUpdatingUI) return; String date = binding.etAdoptionDate.getText().toString(); @@ -154,6 +181,9 @@ public class AdoptionDetailFragment extends Fragment { viewModel.onDateChanged(date, status); } + /** + * Uses fragment arguments to determine if we are editing an existing record. + */ private void handleArguments() { Bundle a = getArguments(); if (a != null && a.containsKey("adoptionId")) { @@ -164,6 +194,9 @@ public class AdoptionDetailFragment extends Fragment { viewModel.setAdoptionId(-1); } + /** + * Load the adoption data from the backend. + */ private void loadAdoptionData() { viewModel.loadAdoption().observe(getViewLifecycleOwner(), resource -> { if (resource == null) return; @@ -174,6 +207,10 @@ public class AdoptionDetailFragment extends Fragment { }); } + /** + * Applies the current ViewState to the UI elements. + * This handles enabling/disabling views and setting text/selections based on state. + */ private void applyViewState(AdoptionDetailViewModel.ViewState state) { isUpdatingUI = true; @@ -224,10 +261,16 @@ public class AdoptionDetailFragment extends Fragment { isUpdatingUI = false; } + /** + * Checks if the currently logged-in user has the STAFF role. + */ private boolean isStaff() { return "STAFF".equalsIgnoreCase(tokenManager.getRole()); } + /** + * Validates input and saves the adoption record. + */ private void saveAdoption() { if (!InputValidator.isSpinnerSelected(binding.spinnerAdoptionCustomer, "Customer")) return; if (!InputValidator.isSpinnerSelected(binding.spinnerAdoptionPet, "Pet")) return; @@ -275,6 +318,9 @@ public class AdoptionDetailFragment extends Fragment { }); } + /** + * Displays a confirmation dialog before deleting the adoption record. + */ private void confirmDelete() { DialogUtils.showDeleteConfirmDialog(requireContext(), "Adoption Record", () -> viewModel.deleteAdoption().observe(getViewLifecycleOwner(), resource -> { @@ -289,6 +335,9 @@ public class AdoptionDetailFragment extends Fragment { })); } + /** + * Navigates back to the previous screen. + */ private void navigateBack() { NavHostFragment.findNavController(this).popBackStack(); } diff --git a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/AppointmentDetailFragment.java b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/AppointmentDetailFragment.java index baec0c28..a426cf8e 100644 --- a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/AppointmentDetailFragment.java +++ b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/AppointmentDetailFragment.java @@ -47,18 +47,27 @@ public class AppointmentDetailFragment extends Fragment { @Inject TokenManager tokenManager; + /** + * Initializes the fragment and its ViewModel. + */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); viewModel = new ViewModelProvider(this).get(AppointmentDetailViewModel.class); } + /** + * Inflates the layout for the fragment + */ @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { binding = FragmentAppointmentDetailBinding.inflate(inflater, container, false); return binding.getRoot(); } + /** + * Sets up UI components, observers, and loads initial data after the view is created. + */ @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); @@ -73,12 +82,18 @@ public class AppointmentDetailFragment extends Fragment { binding.btnDeleteAppointment.setOnClickListener(v -> confirmDelete()); } + /** + * Cleans up the binding reference. + */ @Override public void onDestroyView() { super.onDestroyView(); binding = null; } + /** + * Initializes the spinners with data and selection listeners. + */ private void setupSpinners() { SpinnerUtils.setupStringSpinner(requireContext(), binding.spinnerAppointmentStatus, new String[]{}); @@ -108,11 +123,17 @@ public class AppointmentDetailFragment extends Fragment { SpinnerUtils.setOnIndexSelectedListener(binding.spinnerAppointmentStatus, p -> notifyDateTimeStatusChange()); } + /** + * Configures the date picker for the appointment date field. + */ private void setupDatePicker() { binding.etAppointmentDate.setOnClickListener(v -> UIUtils.showDatePicker(requireContext(), binding.etAppointmentDate, this::notifyDateTimeStatusChange)); } + /** + * Sets up observers for ViewModel to update the UI dynamically. + */ private void observeViewModel() { viewModel.getViewState().observe(getViewLifecycleOwner(), this::applyViewState); @@ -147,12 +168,19 @@ public class AppointmentDetailFragment extends Fragment { }); } + /** + * Shows or hides the loading bar. + */ private void setLoading(boolean loading) { if (binding != null && binding.progressBar != null) { binding.progressBar.setVisibility(loading ? View.VISIBLE : View.GONE); } } + /** + * Applies the current ViewState to the UI elements. + * This handles enabling/disabling views and setting text/selections based on state. + */ private void applyViewState(AppointmentDetailViewModel.ViewState state) { isUpdatingUI = true; @@ -201,10 +229,16 @@ public class AppointmentDetailFragment extends Fragment { isUpdatingUI = false; } + /** + * Checks if the currently logged-in user has the STAFF role. + */ private boolean isStaff() { return "STAFF".equalsIgnoreCase(tokenManager.getRole()); } + /** + * Notifies the ViewModel when the date, time, or status changes to update available options. + */ private void notifyDateTimeStatusChange() { if (isUpdatingUI) return; @@ -215,6 +249,9 @@ public class AppointmentDetailFragment extends Fragment { viewModel.onDateOrTimeChanged(date, time, status); } + /** + * Uses fragment arguments to determine if we are editing an existing record. + */ private void handleArguments() { Bundle a = getArguments(); if (a != null && a.containsKey("appointmentId")) { @@ -225,6 +262,9 @@ public class AppointmentDetailFragment extends Fragment { } } + /** + * Load the appointment data from the backend. + */ private void loadAppointmentData() { viewModel.loadAppointment().observe(getViewLifecycleOwner(), resource -> { if (resource == null) return; @@ -244,6 +284,9 @@ public class AppointmentDetailFragment extends Fragment { }); } + /** + * Validates input and saves the appointment record. + */ private void saveAppointment() { if (!validateRequiredFields()) return; @@ -275,6 +318,9 @@ public class AppointmentDetailFragment extends Fragment { }); } + /** + * Validates that all required fields are selected or filled. + */ private boolean validateRequiredFields() { if (!InputValidator.isSpinnerSelected(binding.spinnerCustomer, "Customer")) return false; if (!InputValidator.isSpinnerSelected(binding.spinnerStore, "Store")) return false; @@ -284,15 +330,24 @@ public class AppointmentDetailFragment extends Fragment { return true; } + /** + * Formats the selected hour and minute from spinners into a time string. + */ private String buildTimeString() { return DateTimeUtils.formatTime(HOURS[binding.spinnerHour.getSelectedItemPosition()], MINUTES[binding.spinnerMinute.getSelectedItemPosition()]); } + /** + * Handles errors that occur during the save process. + */ private void handleSaveError(String errorMessage) { if (errorMessage != null && errorMessage.toLowerCase().contains("not available")) showNoAvailabilityDialog(); else Toast.makeText(getContext(), errorMessage != null ? errorMessage : "Error saving", Toast.LENGTH_SHORT).show(); } + /** + * Displays a dialog when the selected time slot is not available. + */ private void showNoAvailabilityDialog() { new androidx.appcompat.app.AlertDialog.Builder(requireContext()) .setTitle("No Availability") @@ -301,6 +356,9 @@ public class AppointmentDetailFragment extends Fragment { .setNegativeButton("Cancel Booking", (d, w) -> navigateBack()).show(); } + /** + * Displays a confirmation dialog before deleting the appointment record. + */ private void confirmDelete() { DialogUtils.showDeleteConfirmDialog(requireContext(), "Appointment", () -> viewModel.deleteAppointment().observe(getViewLifecycleOwner(), resource -> { @@ -310,10 +368,16 @@ public class AppointmentDetailFragment extends Fragment { })); } + /** + * Navigates back to the previous screen. + */ private void navigateBack() { NavHostFragment.findNavController(this).popBackStack(); } + /** + * Parses a time string and sets the hour and minute spinners accordingly. + */ private void parseAndSetTimeSpinners(String time) { int[] parsedTime = DateTimeUtils.parseTimeString(time); if (parsedTime == null) return; diff --git a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/CouponDetailFragment.java b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/CouponDetailFragment.java index 0d243a69..47145bcf 100644 --- a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/CouponDetailFragment.java +++ b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/CouponDetailFragment.java @@ -29,12 +29,18 @@ import java.util.Locale; import dagger.hilt.android.AndroidEntryPoint; +/** + * Fragment for displaying and editing coupon details. + */ @AndroidEntryPoint public class CouponDetailFragment extends Fragment { private FragmentCouponDetailBinding binding; private CouponDetailViewModel viewModel; private long couponId = -1; + /** + * Inflates the layout, initializes ViewModel, and sets up UI components. + */ @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -74,10 +80,16 @@ public class CouponDetailFragment extends Fragment { return binding.getRoot(); } + /** + * Initializes the discount type spinner with options. + */ private void setupDiscountTypeSpinner() { SpinnerUtils.setupStringSpinner(requireContext(), binding.spinnerDiscountTypeDetail, new String[]{"FIXED", "PERCENT"}); } + /** + * Configures a date picker for an EditText field. + */ private void setupDatePicker(android.widget.EditText editText, android.widget.EditText dependOn, Runnable onDateSet) { editText.setFocusable(false); editText.setClickable(true); @@ -91,6 +103,9 @@ public class CouponDetailFragment extends Fragment { }); } + /** + * Loads coupon details from the backend and populates the UI. + */ private void loadCouponDetails() { binding.tvCouponId.setText(DateTimeUtils.formatId(couponId)); binding.tvCouponId.setVisibility(View.VISIBLE); @@ -111,6 +126,9 @@ public class CouponDetailFragment extends Fragment { }); } + /** + * Validates input and saves the coupon record. + */ private void saveCoupon() { if (!InputValidator.isNotEmpty(binding.etCouponCodeDetail, "Coupon Code")) return; if (!InputValidator.isGreaterThanZero(binding.etDiscountValueDetail, "Discount Value")) return; @@ -156,6 +174,9 @@ public class CouponDetailFragment extends Fragment { }); } + /** + * Displays a confirmation dialog before deleting the coupon. + */ private void confirmDelete() { new AlertDialog.Builder(requireContext()) .setTitle("Delete Coupon") diff --git a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/CustomerDetailFragment.java b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/CustomerDetailFragment.java index 455450cc..017c80e2 100644 --- a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/CustomerDetailFragment.java +++ b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/CustomerDetailFragment.java @@ -21,6 +21,9 @@ import javax.inject.Inject; import dagger.hilt.android.AndroidEntryPoint; +/** + * Fragment for displaying and editing customer details. + */ @AndroidEntryPoint public class CustomerDetailFragment extends Fragment { @@ -31,6 +34,9 @@ public class CustomerDetailFragment extends Fragment { private final String[] STATUSES = {"Active", "Inactive"}; + /** + * Inflates the layout, initializes ViewModel, and sets up UI components. + */ @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -49,10 +55,16 @@ public class CustomerDetailFragment extends Fragment { return binding.getRoot(); } + /** + * Initializes the spinners with data. + */ private void setupSpinners() { SpinnerUtils.setupStringSpinner(requireContext(), binding.spinnerCustomerStatus, STATUSES); } + /** + * Uses fragment arguments to determine if we are editing an existing record. + */ private void handleArguments() { Bundle a = getArguments(); if (a != null && a.getBoolean("isEditing", false)) { @@ -86,6 +98,9 @@ public class CustomerDetailFragment extends Fragment { } } + /** + * Loads customer data from the backend. + */ private void loadCustomerData(long id) { viewModel.loadCustomer(id).observe(getViewLifecycleOwner(), resource -> { if (resource != null) { @@ -105,12 +120,18 @@ public class CustomerDetailFragment extends Fragment { }); } + /** + * Shows or hides the loading bar. + */ private void setLoading(boolean loading) { if (binding != null && binding.progressBar != null) { binding.progressBar.setVisibility(loading ? View.VISIBLE : View.GONE); } } + /** + * Validates input and saves the customer record. + */ private void save() { if (!InputValidator.isNotEmpty(binding.etCustomerUsername, "Username")) return; @@ -160,6 +181,9 @@ public class CustomerDetailFragment extends Fragment { }); } + /** + * Displays a confirmation dialog before deleting the customer. + */ private void confirmDelete() { DialogUtils.showDeleteConfirmDialog(requireContext(), "Customer", () -> viewModel.deleteCustomer().observe(getViewLifecycleOwner(), resource -> { @@ -175,10 +199,16 @@ public class CustomerDetailFragment extends Fragment { })); } + /** + * Navigates back to the previous screen. + */ private void navigateBack() { NavHostFragment.findNavController(this).popBackStack(); } + /** + * Cleans up the binding reference. + */ @Override public void onDestroyView() { super.onDestroyView(); diff --git a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/InventoryDetailFragment.java b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/InventoryDetailFragment.java index 75f1a6b3..f0e37927 100644 --- a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/InventoryDetailFragment.java +++ b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/InventoryDetailFragment.java @@ -37,12 +37,18 @@ public class InventoryDetailFragment extends Fragment { private long preselectedStoreId = -1; private long preselectedProductId = -1; + /** + * Initializes the fragment and its ViewModel. + */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); viewModel = new ViewModelProvider(this).get(InventoryDetailViewModel.class); } + /** + * Inflates the layout for the fragment. + */ @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -50,6 +56,9 @@ public class InventoryDetailFragment extends Fragment { return binding.getRoot(); } + /** + * Sets up UI components, observers, and loads initial data after the view is created. + */ @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); @@ -63,23 +72,35 @@ public class InventoryDetailFragment extends Fragment { binding.btnDeleteInventory.setOnClickListener(v -> confirmDelete()); } + /** + * Sets up observers for ViewModel to update the UI dynamically. + */ private void observeViewModel() { viewModel.getStoreList().observe(getViewLifecycleOwner(), list -> refreshStoreSpinner()); viewModel.getProductList().observe(getViewLifecycleOwner(), list -> refreshProductSpinner()); } + /** + * Shows or hides the loading bar. + */ private void setLoading(boolean loading) { if (binding != null && binding.progressBar != null) { binding.progressBar.setVisibility(loading ? View.VISIBLE : View.GONE); } } + /** + * Cleans up the binding reference. + */ @Override public void onDestroyView() { super.onDestroyView(); binding = null; } + /** + * Loads initial data for the store and product spinners. + */ private void loadSpinnersData() { viewModel.loadStores().observe(getViewLifecycleOwner(), resource -> { if (resource == null) return; @@ -97,18 +118,27 @@ public class InventoryDetailFragment extends Fragment { }); } + /** + * Refreshes the store spinner with the current data. + */ private void refreshStoreSpinner() { SpinnerUtils.populateSpinner(requireContext(), binding.spinnerInventoryStore, viewModel.getStoreList().getValue(), DropdownDTO::getLabel, "-- Select Store --", preselectedStoreId, DropdownDTO::getId); } + /** + * Refreshes the product spinner with the current data. + */ private void refreshProductSpinner() { SpinnerUtils.populateSpinner(requireContext(), binding.spinnerInventoryProduct, viewModel.getProductList().getValue(), DropdownDTO::getLabel, "-- Select Product --", preselectedProductId, DropdownDTO::getId); } + /** + * Uses fragment arguments to determine if we are editing an existing record. + */ private void handleArguments() { Bundle args = getArguments(); if (args != null && args.containsKey("inventoryId")) { @@ -131,6 +161,9 @@ public class InventoryDetailFragment extends Fragment { } } + /** + * Loads the inventory data from the backend. + */ private void loadInventoryData() { viewModel.loadInventory().observe(getViewLifecycleOwner(), resource -> { if (resource == null) return; @@ -149,6 +182,9 @@ public class InventoryDetailFragment extends Fragment { }); } + /** + * Validates input and saves the inventory record. + */ private void saveInventory() { if (!InputValidator.isSpinnerSelected(binding.spinnerInventoryStore, "Store")) return; if (!InputValidator.isSpinnerSelected(binding.spinnerInventoryProduct, "Product")) return; @@ -176,10 +212,16 @@ public class InventoryDetailFragment extends Fragment { }); } + /** + * Displays a confirmation dialog before deleting the inventory record. + */ private void confirmDelete() { DialogUtils.showDeleteConfirmDialog(requireContext(), "Inventory Item", this::deleteInventory); } + /** + * Calls the ViewModel to delete the inventory record. + */ private void deleteInventory() { setButtonsEnabled(false); viewModel.deleteInventory().observe(getViewLifecycleOwner(), resource -> { @@ -197,10 +239,16 @@ public class InventoryDetailFragment extends Fragment { }); } + /** + * Navigates back to the previous screen. + */ private void navigateBack() { NavHostFragment.findNavController(this).popBackStack(); } + /** + * Enables or disables the action buttons. + */ private void setButtonsEnabled(boolean enabled) { UIUtils.setViewsEnabled(enabled, binding.btnSaveInventory, binding.btnDeleteInventory, binding.btnInventoryBack); } diff --git a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/ProductDetailFragment.java b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/ProductDetailFragment.java index 5d89e305..7119a447 100644 --- a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/ProductDetailFragment.java +++ b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/ProductDetailFragment.java @@ -58,6 +58,9 @@ public class ProductDetailFragment extends Fragment { @Inject @Named("baseUrl") String baseUrl; @Inject TokenManager tokenManager; + /** + * Initializes the fragment, its ViewModel, and the ImagePickerHelper. + */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -88,6 +91,9 @@ public class ProductDetailFragment extends Fragment { }); } + /** + * Inflates the layout for the fragment. + */ @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -95,6 +101,9 @@ public class ProductDetailFragment extends Fragment { return binding.getRoot(); } + /** + * Sets up UI components, observers, and handles arguments after the view is created. + */ @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); @@ -108,6 +117,9 @@ public class ProductDetailFragment extends Fragment { binding.ivProductImage.setOnClickListener(v -> imagePickerHelper.showImagePickerDialog("Select Product Image", hasImage)); } + /** + * Sets up observers for the ViewModel and loads product categories. + */ private void observeViewModel() { viewModel.getCategoryList().observe(getViewLifecycleOwner(), list -> updateCategorySpinner()); @@ -120,24 +132,36 @@ public class ProductDetailFragment extends Fragment { }); } + /** + * Shows or hides the loading bar. + */ private void setLoading(boolean loading) { if (binding != null && binding.progressBar != null) { binding.progressBar.setVisibility(loading ? View.VISIBLE : View.GONE); } } + /** + * Populates the category spinner with available categories. + */ private void updateCategorySpinner() { SpinnerUtils.populateSpinner(requireContext(), binding.spinnerProductCategory, viewModel.getCategoryList().getValue(), DropdownDTO::getLabel, "-- Select Category --", preselectedCategoryId, DropdownDTO::getId); } + /** + * Cleans up the binding reference. + */ @Override public void onDestroyView() { super.onDestroyView(); binding = null; } + /** + * Uses fragment arguments to determine if we are editing an existing record. + */ private void handleArguments() { Bundle a = getArguments(); if (a != null && a.containsKey("prodId")) { @@ -158,6 +182,9 @@ public class ProductDetailFragment extends Fragment { } } + /** + * Loads the product details from the backend. + */ private void loadProductData() { viewModel.loadProduct().observe(getViewLifecycleOwner(), resource -> { if (resource == null) return; @@ -175,6 +202,9 @@ public class ProductDetailFragment extends Fragment { }); } + /** + * Loads the product image from the server. + */ private void loadProductImage() { String imageUrl = baseUrl + String.format(Locale.US, ProductApi.PRODUCT_IMAGE_PATH, viewModel.getProdId()); String token = tokenManager.getToken(); @@ -192,6 +222,9 @@ public class ProductDetailFragment extends Fragment { }); } + /** + * Performs image-related actions (removal or upload) after a successful product save. + */ private void performPendingImageActions(String successMsg) { if (isImageRemoved) { viewModel.deleteProductImage().observe(getViewLifecycleOwner(), resource -> { @@ -214,6 +247,9 @@ public class ProductDetailFragment extends Fragment { } } + /** + * Uploads the selected product image to the server. + */ private void uploadProductImageAndNavigate(Uri uri, String successMsg) { File file = FileUtils.getFileFromUri(requireContext(), uri); if (file == null) { @@ -239,6 +275,9 @@ public class ProductDetailFragment extends Fragment { }); } + /** + * Validates input and saves the product record. + */ private void saveProduct() { if (!InputValidator.isNotEmpty(binding.etProductName, "Product Name")) return; if (!InputValidator.isSpinnerSelected(binding.spinnerProductCategory, "Category")) return; @@ -267,6 +306,9 @@ public class ProductDetailFragment extends Fragment { }); } + /** + * Displays a confirmation dialog before deleting the product. + */ private void confirmDelete() { DialogUtils.showDeleteConfirmDialog(requireContext(), "Product", () -> viewModel.deleteProduct().observe(getViewLifecycleOwner(), resource -> { @@ -280,6 +322,9 @@ public class ProductDetailFragment extends Fragment { })); } + /** + * Navigates back to the previous screen. + */ private void navigateBack() { NavHostFragment.findNavController(this).popBackStack(); } diff --git a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/ProductSupplierDetailFragment.java b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/ProductSupplierDetailFragment.java index 6abb918c..e0ba9409 100644 --- a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/ProductSupplierDetailFragment.java +++ b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/ProductSupplierDetailFragment.java @@ -35,12 +35,18 @@ public class ProductSupplierDetailFragment extends Fragment { private long preselectedProductId = -1; private long preselectedSupplierId = -1; + /** + * Initializes the view model. + */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); viewModel = new ViewModelProvider(this).get(ProductSupplierDetailViewModel.class); } + /** + * Inflates the layout for this fragment. + */ @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -48,6 +54,9 @@ public class ProductSupplierDetailFragment extends Fragment { return binding.getRoot(); } + /** + * Initializes the UI components and observers after the view is created. + */ @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); @@ -60,23 +69,35 @@ public class ProductSupplierDetailFragment extends Fragment { binding.btnDeletePS.setOnClickListener(v -> confirmDelete()); } + /** + * Observes LiveData from the ViewModel to update the UI. + */ private void observeViewModel() { viewModel.getProductList().observe(getViewLifecycleOwner(), list -> refreshProductSpinner()); viewModel.getSupplierList().observe(getViewLifecycleOwner(), list -> refreshSupplierSpinner()); } + /** + * Toggles the visibility of the progress bar. + */ private void setLoading(boolean loading) { if (binding != null && binding.progressBar != null) { binding.progressBar.setVisibility(loading ? View.VISIBLE : View.GONE); } } + /** + * Cleans up the binding when the view is destroyed. + */ @Override public void onDestroyView() { super.onDestroyView(); binding = null; } + /** + * Loads lookup data for products and suppliers. + */ private void loadSpinnersData() { viewModel.loadProducts().observe(getViewLifecycleOwner(), resource -> { if (resource == null) return; @@ -94,18 +115,27 @@ public class ProductSupplierDetailFragment extends Fragment { }); } + /** + * Refreshes the product spinner with data from the view model. + */ private void refreshProductSpinner() { SpinnerUtils.populateSpinner(requireContext(), binding.spinnerPSProduct, viewModel.getProductList().getValue(), ProductDTO::getProdName, "-- Select Product --", preselectedProductId, ProductDTO::getProdId); } + /** + * Refreshes the supplier spinner with data from the view model. + */ private void refreshSupplierSpinner() { SpinnerUtils.populateSpinner(requireContext(), binding.spinnerPSSupplier, viewModel.getSupplierList().getValue(), SupplierDTO::getSupCompany, "-- Select Supplier --", preselectedSupplierId, SupplierDTO::getSupId); } + /** + * Handles fragment arguments to determine mode (new vs edit). + */ private void handleArguments() { Bundle a = getArguments(); if (a != null && a.containsKey("productId") && a.containsKey("supplierId")) { @@ -132,6 +162,9 @@ public class ProductSupplierDetailFragment extends Fragment { } } + /** + * Validates and saves the product-supplier relationship. + */ private void save() { if (!InputValidator.isSpinnerSelected(binding.spinnerPSProduct, "Product")) return; if (!InputValidator.isSpinnerSelected(binding.spinnerPSSupplier, "Supplier")) return; @@ -155,6 +188,9 @@ public class ProductSupplierDetailFragment extends Fragment { }); } + /** + * Shows a confirmation dialog before deleting the relationship. + */ private void confirmDelete() { DialogUtils.showDeleteConfirmDialog(requireContext(), "Product Supplier Relationship", () -> viewModel.deleteProductSupplier().observe(getViewLifecycleOwner(), resource -> { @@ -169,6 +205,9 @@ public class ProductSupplierDetailFragment extends Fragment { })); } + /** + * Navigates back to the previous fragment. + */ private void navigateBack() { NavHostFragment.findNavController(this).popBackStack(); } diff --git a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/PurchaseOrderDetailFragment.java b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/PurchaseOrderDetailFragment.java index d1bbd31c..aca42375 100644 --- a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/PurchaseOrderDetailFragment.java +++ b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/PurchaseOrderDetailFragment.java @@ -27,6 +27,9 @@ public class PurchaseOrderDetailFragment extends Fragment { private PurchaseOrderDetailViewModel viewModel; private long purchaseOrderId; + /** + * Initializes the view model. + */ @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -57,6 +60,9 @@ public class PurchaseOrderDetailFragment extends Fragment { }); } + /** + * Handles fragment arguments to retrieve the purchase order ID. + */ private void handleArguments() { Bundle a = getArguments(); if (a != null && a.containsKey("purchaseOrderId")) { @@ -65,12 +71,18 @@ public class PurchaseOrderDetailFragment extends Fragment { } } + /** + * Toggles the visibility of the progress bar. + */ private void setLoading(boolean loading) { if (binding != null && binding.progressBar != null) { binding.progressBar.setVisibility(loading ? View.VISIBLE : View.GONE); } } + /** + * Loads the details of the specified purchase order. + */ private void loadPurchaseOrderData() { viewModel.loadPurchaseOrder(purchaseOrderId).observe(getViewLifecycleOwner(), resource -> { if (resource == null) return; @@ -87,6 +99,9 @@ public class PurchaseOrderDetailFragment extends Fragment { }); } + /** + * Cleans up the binding when the view is destroyed. + */ @Override public void onDestroyView() { super.onDestroyView(); diff --git a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/RefundFragment.java b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/RefundFragment.java index 0dbd985f..6165be7b 100644 --- a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/RefundFragment.java +++ b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/RefundFragment.java @@ -21,6 +21,9 @@ import java.math.BigDecimal; import java.math.RoundingMode; import java.util.*; +/** + * Fragment for processing refunds for existing sales. + */ @AndroidEntryPoint public class RefundFragment extends Fragment { @@ -29,6 +32,9 @@ public class RefundFragment extends Fragment { private final String[] PAYMENT_METHODS = {"Cash", "Card"}; + /** + * Initializes the fragment's UI and view model. + */ @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -51,25 +57,37 @@ public class RefundFragment extends Fragment { return binding.getRoot(); } + /** + * Sets up the payment method spinner. + */ private void setupSpinner() { SpinnerUtils.setupStringSpinner(requireContext(), binding.spinnerRefundPayment, PAYMENT_METHODS); } + /** + * Observes LiveData from the ViewModel to update the UI. + */ private void observeViewModel() { viewModel.getAvailableItems().observe(getViewLifecycleOwner(), items -> renderOriginalItems()); viewModel.getRefundCart().observe(getViewLifecycleOwner(), cart -> { renderRefundCart(); updateRefundTotal(); - renderOriginalItems(); // Re-render to reflect quantities in cart + renderOriginalItems(); }); } + /** + * Toggles the visibility of the progress bar. + */ private void setLoading(boolean loading) { if (binding != null && binding.progressBar != null) { binding.progressBar.setVisibility(loading ? View.VISIBLE : View.GONE); } } + /** + * Loads the list of all sales to allow looking up the sale to refund. + */ private void loadAllSales() { viewModel.loadAllSales().observe(getViewLifecycleOwner(), resource -> { if (resource == null) return; @@ -84,6 +102,9 @@ public class RefundFragment extends Fragment { }); } + /** + * Loads the details of a specific sale for refund processing. + */ private void loadSale() { String idStr = binding.etRefundSaleId.getText().toString().trim(); if (idStr.isEmpty()) { @@ -145,6 +166,9 @@ public class RefundFragment extends Fragment { binding.btnProcessRefund.setVisibility(View.VISIBLE); } + /** + * Renders the items from the original sale that are available for refund. + */ private void renderOriginalItems() { binding.llOriginalItems.removeAllViews(); List available = viewModel.getAvailableItems().getValue(); @@ -173,6 +197,9 @@ public class RefundFragment extends Fragment { } } + /** + * Renders the items selected for the refund. + */ private void renderRefundCart() { binding.llRefundItems.removeAllViews(); List cart = viewModel.getRefundCart().getValue(); @@ -200,6 +227,9 @@ public class RefundFragment extends Fragment { } } + /** + * Adds a header row to the layout representing a table. + */ private void addTableHeader(LinearLayout parent) { if (getContext() == null) return; LinearLayout header = new LinearLayout(getContext()); @@ -220,6 +250,9 @@ public class RefundFragment extends Fragment { parent.addView(header); } + /** + * Builds a UI row for an item in the original list or refund cart. + */ private LinearLayout buildItemRow(String name, int qty, BigDecimal unitPrice, boolean isAdd, Runnable action) { if (getContext() == null) return new LinearLayout(getContext()); @@ -267,6 +300,9 @@ public class RefundFragment extends Fragment { return row; } + /** + * Shows a dialog to select the quantity of an item to refund. + */ private void showQuantityDialog(RefundViewModel.RefundItem item, int available) { EditText input = new EditText(getContext()); input.setInputType(android.text.InputType.TYPE_CLASS_NUMBER); @@ -301,11 +337,17 @@ public class RefundFragment extends Fragment { .show(); } + /** + * Updates the total refund amount display. + */ private void updateRefundTotal() { BigDecimal total = viewModel.calculateRefundTotal(); binding.tvRefundTotal.setText("Refund Total: $" + total.setScale(2, RoundingMode.HALF_UP)); } + /** + * Validates and prepares the refund for processing. + */ private void processRefund() { if (viewModel.getCurrentSale() == null) { Toast.makeText(getContext(), "Load a sale first", Toast.LENGTH_SHORT).show(); @@ -325,6 +367,9 @@ public class RefundFragment extends Fragment { () -> submitRefund(payment)); } + /** + * Submits the refund request to the backend. + */ private void submitRefund(String payment) { viewModel.submitRefund(payment).observe(getViewLifecycleOwner(), resource -> { if (resource != null) { @@ -339,10 +384,16 @@ public class RefundFragment extends Fragment { }); } + /** + * Navigates back to the previous fragment. + */ private void navigateBack() { NavHostFragment.findNavController(this).popBackStack(); } + /** + * Cleans up the binding when the view is destroyed. + */ @Override public void onDestroyView() { super.onDestroyView(); diff --git a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/SaleDetailFragment.java b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/SaleDetailFragment.java index 4963b272..b1ecb2b9 100644 --- a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/SaleDetailFragment.java +++ b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/SaleDetailFragment.java @@ -26,6 +26,9 @@ import dagger.hilt.android.AndroidEntryPoint; import java.math.BigDecimal; import java.util.*; +/** + * Fragment for viewing or creating sale details. + */ @AndroidEntryPoint public class SaleDetailFragment extends Fragment { @@ -36,6 +39,9 @@ public class SaleDetailFragment extends Fragment { private final String[] PAYMENT_METHODS = { "Cash", "Card"}; + /** + * Initializes the fragment's UI and view model. + */ @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -65,14 +71,23 @@ public class SaleDetailFragment extends Fragment { return binding.getRoot(); } + /** + * Checks if the current user has the 'STAFF' role. + */ private boolean isStaff() { return "STAFF".equalsIgnoreCase(tokenManager.getRole()); } + /** + * Checks if the current user has the 'ADMIN' role. + */ private boolean isAdmin() { return "ADMIN".equalsIgnoreCase(tokenManager.getRole()); } + /** + * Observes LiveData from the ViewModel to update the UI. + */ private void observeViewModel() { viewModel.getStoreList().observe(getViewLifecycleOwner(), list -> { Long primaryStoreId = tokenManager.getPrimaryStoreId(); @@ -115,6 +130,9 @@ public class SaleDetailFragment extends Fragment { }); } + /** + * Handles fragment arguments to determine mode (new sale vs view existing). + */ private void handleArguments() { Bundle a = getArguments(); if (a != null && a.containsKey("saleId")) { @@ -159,12 +177,18 @@ public class SaleDetailFragment extends Fragment { } } + /** + * Toggles the visibility of the progress bar. + */ private void setLoading(boolean loading) { if (binding != null && binding.progressBar != null) { binding.progressBar.setVisibility(loading ? View.VISIBLE : View.GONE); } } + /** + * Loads lookup data for stores, customers, and products. + */ private void loadData() { viewModel.loadStores().observe(getViewLifecycleOwner(), resource -> { if (resource == null) return; @@ -183,6 +207,9 @@ public class SaleDetailFragment extends Fragment { }); } + /** + * Loads the details of an existing sale. + */ private void loadSaleDetails() { viewModel.loadSaleDetails().observe(getViewLifecycleOwner(), resource -> { if (resource == null) return; @@ -241,6 +268,9 @@ public class SaleDetailFragment extends Fragment { }); } + /** + * Sets up the coupon application logic. + */ private void setupCoupon() { binding.btnApplyCoupon.setOnClickListener(v -> { String code = binding.etCouponCode.getText().toString().trim(); @@ -284,6 +314,9 @@ public class SaleDetailFragment extends Fragment { }); } + /** + * Updates the UI to reflect an applied coupon. + */ private void applyAppliedCouponUI(CouponDTO coupon) { String info; if ("PERCENTAGE".equalsIgnoreCase(coupon.getDiscountType())) { @@ -299,12 +332,18 @@ public class SaleDetailFragment extends Fragment { binding.etCouponCode.setEnabled(false); } + /** + * Displays an error message related to coupon validation. + */ private void showCouponError(String message) { binding.tvCouponInfo.setText(message); binding.tvCouponInfo.setTextColor(0xFFE53935); binding.tvCouponInfo.setVisibility(View.VISIBLE); } + /** + * Sets up the logic for adding items to the sale cart. + */ private void setupAddItem() { binding.btnAddItem.setOnClickListener(v -> { if (!InputValidator.isSpinnerSelected(binding.spinnerSaleProduct, "Product")) return; @@ -338,6 +377,9 @@ public class SaleDetailFragment extends Fragment { }); } + /** + * Renders the list of items currently in the cart. + */ private void renderCartItems() { binding.llSaleItems.removeAllViews(); List items = viewModel.getCartItems().getValue(); @@ -358,6 +400,9 @@ public class SaleDetailFragment extends Fragment { } } + /** + * Adds a row representing a sale item to the layout. + */ private void addItemRow(String name, int qty, BigDecimal price, Long prodId) { if (getContext() == null) return; LinearLayout row = new LinearLayout(getContext()); @@ -397,6 +442,9 @@ public class SaleDetailFragment extends Fragment { binding.llSaleItems.addView(row); } + /** + * Updates the subtotal, discounts, and total amount display. + */ private void updateTotal() { BigDecimal subtotal = viewModel.calculateSubtotal(); BigDecimal couponDiscount = viewModel.calculateCouponDiscount(); @@ -432,6 +480,9 @@ public class SaleDetailFragment extends Fragment { } } + /** + * Validates and saves the new sale. + */ private void saveSale() { if (!InputValidator.isSpinnerSelected(binding.spinnerSaleStore, "Store")) return; @@ -468,6 +519,9 @@ public class SaleDetailFragment extends Fragment { }); } + /** + * Shows a confirmation dialog before proceeding to the refund screen. + */ private void showRefundDialog() { DialogUtils.showConfirmDialog(requireContext(), "Process Refund", "Are you sure you want to process a refund for this sale?", () -> { @@ -477,10 +531,16 @@ public class SaleDetailFragment extends Fragment { }); } + /** + * Navigates back to the previous fragment. + */ private void navigateBack() { NavHostFragment.findNavController(this).popBackStack(); } + /** + * Cleans up the binding when the view is destroyed. + */ @Override public void onDestroyView() { super.onDestroyView(); diff --git a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/ServiceDetailFragment.java b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/ServiceDetailFragment.java index d7ee6e4c..0a0612c5 100644 --- a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/ServiceDetailFragment.java +++ b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/ServiceDetailFragment.java @@ -35,12 +35,18 @@ public class ServiceDetailFragment extends Fragment { private FragmentServiceDetailBinding binding; private ServiceDetailViewModel viewModel; + /** + * Initializes the fragment and its ViewModel. + */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); viewModel = new ViewModelProvider(this).get(ServiceDetailViewModel.class); } + /** + * Inflates the layout for the fragment. + */ @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -48,6 +54,9 @@ public class ServiceDetailFragment extends Fragment { return binding.getRoot(); } + /** + * Sets up UI components, observers, and handles arguments after the view is created. + */ @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); @@ -60,22 +69,34 @@ public class ServiceDetailFragment extends Fragment { binding.btnDeleteService.setOnClickListener(v -> deleteService()); } + /** + * Sets up observers for ViewModel to update the UI dynamically. + */ private void observeViewModel() { viewModel.getViewState().observe(getViewLifecycleOwner(), this::applyViewState); } + /** + * Shows or hides the loading bar. + */ private void setLoading(boolean loading) { if (binding != null) { binding.progressBar.setVisibility(loading ? View.VISIBLE : View.GONE); } } + /** + * Cleans up the binding reference. + */ @Override public void onDestroyView() { super.onDestroyView(); binding = null; } + /** + * Validates input and saves the service record. + */ private void saveService() { if (!InputValidator.isNotEmpty(binding.etServiceName, "Service Name")) return; if (!InputValidator.isNotEmpty(binding.etServiceDesc, "Description")) return; @@ -111,6 +132,9 @@ public class ServiceDetailFragment extends Fragment { }); } + /** + * Displays a confirmation dialog before deleting the service record. + */ private void deleteService() { DialogUtils.showDeleteConfirmDialog(requireContext(), "Service", () -> viewModel.deleteService().observe(getViewLifecycleOwner(), resource -> { @@ -126,10 +150,16 @@ public class ServiceDetailFragment extends Fragment { })); } + /** + * Navigates back to the previous screen. + */ private void navigateBack() { NavHostFragment.findNavController(this).popBackStack(); } + /** + * Uses fragment arguments to determine if we are editing an existing record. + */ private void handleArguments() { if (getArguments() != null && getArguments().containsKey("serviceId")) { viewModel.setServiceId(getArguments().getLong("serviceId")); @@ -140,6 +170,9 @@ public class ServiceDetailFragment extends Fragment { viewModel.setServiceId(-1); } + /** + * Loads the service details from the backend. + */ private void loadServiceData() { viewModel.loadService().observe(getViewLifecycleOwner(), resource -> { if (resource == null) return; @@ -150,6 +183,9 @@ public class ServiceDetailFragment extends Fragment { }); } + /** + * Applies the current ViewState to the UI elements. + */ private void applyViewState(ServiceDetailViewModel.ViewState state) { binding.tvMode.setText(state.modeTitle); binding.tvServiceId.setText(DateTimeUtils.formatId(viewModel.getServiceId())); @@ -169,6 +205,9 @@ public class ServiceDetailFragment extends Fragment { updateIfDifferent(binding.etServicePrice, state.servicePrice); } + /** + * Updates an EditText field only if the new value is different from the current one. + */ private void updateIfDifferent(EditText field, String value) { String current = field.getText() != null ? field.getText().toString() : ""; String next = value != null ? value : ""; diff --git a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/StaffDetailFragment.java b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/StaffDetailFragment.java index 9bb3435d..0f69f7b5 100644 --- a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/StaffDetailFragment.java +++ b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/StaffDetailFragment.java @@ -22,6 +22,9 @@ import java.util.List; import dagger.hilt.android.AndroidEntryPoint; +/** + * Fragment for displaying and editing staff details. + */ @AndroidEntryPoint public class StaffDetailFragment extends Fragment { @@ -32,6 +35,9 @@ public class StaffDetailFragment extends Fragment { private long preselectedStoreId = -1; + /** + * Inflates the layout, initializes ViewModel, and sets up UI components. + */ @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -52,14 +58,23 @@ public class StaffDetailFragment extends Fragment { return binding.getRoot(); } + /** + * Sets up observers for the ViewModel to refresh the store spinner. + */ private void observeViewModel() { viewModel.getStoreList().observe(getViewLifecycleOwner(), list -> refreshStoreSpinner()); } + /** + * Initializes the status spinner with options. + */ private void setupSpinners() { SpinnerUtils.setupStringSpinner(requireContext(), binding.spinnerStaffStatus, STATUSES); } + /** + * Loads the list of stores from the backend. + */ private void loadStores() { viewModel.loadStores().observe(getViewLifecycleOwner(), resource -> { if (resource != null && resource.status == Resource.Status.SUCCESS && resource.data != null) { @@ -68,6 +83,9 @@ public class StaffDetailFragment extends Fragment { }); } + /** + * Populates the store spinner with available stores. + */ private void refreshStoreSpinner() { List list = viewModel.getStoreList().getValue(); if (list == null) return; @@ -76,6 +94,9 @@ public class StaffDetailFragment extends Fragment { preselectedStoreId, DropdownDTO::getId); } + /** + * Uses fragment arguments to determine if we are editing an existing record. + */ private void handleArguments() { Bundle a = getArguments(); if (a != null && a.getBoolean("isEditing", false)) { @@ -96,6 +117,9 @@ public class StaffDetailFragment extends Fragment { } } + /** + * Loads staff member details from the backend. + */ private void loadEmployeeData(long id) { viewModel.loadEmployee(id).observe(getViewLifecycleOwner(), resource -> { if (resource != null) { @@ -117,12 +141,18 @@ public class StaffDetailFragment extends Fragment { }); } + /** + * Shows or hides the loading bar. + */ private void setLoading(boolean loading) { if (binding != null && binding.progressBar != null) { binding.progressBar.setVisibility(loading ? View.VISIBLE : View.GONE); } } + /** + * Validates input and saves the staff record. + */ private void save() { if (!InputValidator.isNotEmpty(binding.etStaffUsername, "Username")) return; @@ -198,6 +228,9 @@ public class StaffDetailFragment extends Fragment { }); } + /** + * Displays a confirmation dialog before deleting the staff account. + */ private void confirmDelete() { DialogUtils.showDeleteConfirmDialog(requireContext(), "Staff Account", () -> viewModel.deleteEmployee().observe(getViewLifecycleOwner(), resource -> { @@ -213,10 +246,16 @@ public class StaffDetailFragment extends Fragment { })); } + /** + * Navigates back to the previous screen. + */ private void navigateBack() { NavHostFragment.findNavController(this).popBackStack(); } + /** + * Cleans up the binding reference. + */ @Override public void onDestroyView() { super.onDestroyView(); diff --git a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/SupplierDetailFragment.java b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/SupplierDetailFragment.java index 5eb1f43b..513e627c 100644 --- a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/SupplierDetailFragment.java +++ b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/SupplierDetailFragment.java @@ -35,12 +35,18 @@ public class SupplierDetailFragment extends Fragment { private FragmentSupplierDetailBinding binding; private SupplierDetailViewModel viewModel; + /** + * Initializes the view model. + */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); viewModel = new ViewModelProvider(this).get(SupplierDetailViewModel.class); } + /** + * Inflates the layout for this fragment. + */ @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -48,6 +54,9 @@ public class SupplierDetailFragment extends Fragment { return binding.getRoot(); } + /** + * Initializes the UI components and observers after the view is created. + */ @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); @@ -61,22 +70,34 @@ public class SupplierDetailFragment extends Fragment { binding.btnDeleteSupplier.setOnClickListener(v -> deleteSupplier()); } + /** + * Observes LiveData from the ViewModel to update the UI. + */ private void observeViewModel() { viewModel.getViewState().observe(getViewLifecycleOwner(), this::applyViewState); } + /** + * Toggles the visibility of the progress bar. + */ private void setLoading(boolean loading) { if (binding != null) { binding.progressBar.setVisibility(loading ? View.VISIBLE : View.GONE); } } + /** + * Cleans up the binding when the view is destroyed. + */ @Override public void onDestroyView() { super.onDestroyView(); binding = null; } + /** + * Validates and saves the supplier information. + */ private void saveSupplier() { if (!InputValidator.isNotEmpty(binding.etSupCompany, "Company Name")) return; if (!InputValidator.isNotEmpty(binding.etSupContactFirstName, "First Name")) return; @@ -115,6 +136,9 @@ public class SupplierDetailFragment extends Fragment { }); } + /** + * Deletes the current supplier after confirmation. + */ private void deleteSupplier() { DialogUtils.showDeleteConfirmDialog(requireContext(), "Supplier", () -> viewModel.deleteSupplier().observe(getViewLifecycleOwner(), resource -> { @@ -130,10 +154,16 @@ public class SupplierDetailFragment extends Fragment { })); } + /** + * Navigates back to the previous fragment. + */ private void navigateBack() { NavHostFragment.findNavController(this).popBackStack(); } + /** + * Handles fragment arguments to determine mode (new vs edit). + */ private void handleArguments() { if (getArguments() != null && getArguments().containsKey("supId")) { viewModel.setSupId(getArguments().getLong("supId")); @@ -144,6 +174,9 @@ public class SupplierDetailFragment extends Fragment { viewModel.setSupId(-1); } + /** + * Loads the details of the specified supplier. + */ private void loadSupplierData() { viewModel.loadSupplier().observe(getViewLifecycleOwner(), resource -> { if (resource == null) return; @@ -154,6 +187,9 @@ public class SupplierDetailFragment extends Fragment { }); } + /** + * Applies the current view state to the UI components. + */ private void applyViewState(SupplierDetailViewModel.ViewState state) { binding.tvMode.setText(state.modeTitle); binding.tvSupId.setText(DateTimeUtils.formatId(viewModel.getSupId())); @@ -175,6 +211,9 @@ public class SupplierDetailFragment extends Fragment { updateIfDifferent(binding.etSupPhone, state.supPhone); } + /** + * Updates an EditText field only if the new value is different from the current one. + */ private void updateIfDifferent(EditText field, String value) { String current = field.getText() != null ? field.getText().toString() : ""; String next = value != null ? value : ""; diff --git a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/listprofilefragments/PetProfileFragment.java b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/listprofilefragments/PetProfileFragment.java index 496304a3..7cfa0910 100644 --- a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/listprofilefragments/PetProfileFragment.java +++ b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/listprofilefragments/PetProfileFragment.java @@ -36,6 +36,9 @@ import okhttp3.MediaType; import okhttp3.MultipartBody; import okhttp3.RequestBody; +/** + * Fragment for displaying and managing a pet's profile. + */ @AndroidEntryPoint public class PetProfileFragment extends Fragment { @@ -49,6 +52,9 @@ public class PetProfileFragment extends Fragment { private PetProfileViewModel viewModel; private ImagePickerHelper imagePickerHelper; + /** + * Initializes the ViewModel and image picker helper. + */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -67,6 +73,9 @@ public class PetProfileFragment extends Fragment { }); } + /** + * Inflates the layout, handles arguments, and sets up click listeners. + */ @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -95,18 +104,27 @@ public class PetProfileFragment extends Fragment { return binding.getRoot(); } + /** + * Shows or hides the loading progress bar. + */ private void setLoading(boolean loading) { if (binding != null && binding.progressBar != null) { binding.progressBar.setVisibility(loading ? View.VISIBLE : View.GONE); } } + /** + * Cleans up the binding reference. + */ @Override public void onDestroyView() { super.onDestroyView(); binding = null; } + /** + * Loads pet data from the ViewModel and updates the UI. + */ private void loadPetData() { viewModel.getPetById(petId).observe(getViewLifecycleOwner(), resource -> { if (resource == null) return; @@ -153,6 +171,9 @@ public class PetProfileFragment extends Fragment { }); } + /** + * Loads the pet's image using Glide with authentication. + */ private void loadPetImage(int petId) { String imageUrl = baseUrl + String.format(Locale.US, PetApi.PET_IMAGE_PATH, petId); String token = tokenManager.getToken(); @@ -170,6 +191,9 @@ public class PetProfileFragment extends Fragment { }); } + /** + * Uploads a new image for the pet. + */ private void uploadPetImage(Uri uri) { try { File file = FileUtils.getFileFromUri(requireContext(), uri); @@ -193,6 +217,9 @@ public class PetProfileFragment extends Fragment { } } + /** + * Deletes the pet's current image. + */ private void deletePetImage() { viewModel.deletePetImage(petId).observe(getViewLifecycleOwner(), resource -> { if (resource == null) return; diff --git a/android/app/src/main/java/com/example/petstoremobile/models/Chat.java b/android/app/src/main/java/com/example/petstoremobile/models/Chat.java index a519093c..9d782b05 100644 --- a/android/app/src/main/java/com/example/petstoremobile/models/Chat.java +++ b/android/app/src/main/java/com/example/petstoremobile/models/Chat.java @@ -1,5 +1,8 @@ package com.example.petstoremobile.models; +/** + * Model class representing a chat conversation. + */ public class Chat { private String chatId; private String customerName; diff --git a/android/app/src/main/java/com/example/petstoremobile/models/Message.java b/android/app/src/main/java/com/example/petstoremobile/models/Message.java index e6547d23..2e0ff23e 100644 --- a/android/app/src/main/java/com/example/petstoremobile/models/Message.java +++ b/android/app/src/main/java/com/example/petstoremobile/models/Message.java @@ -1,5 +1,8 @@ package com.example.petstoremobile.models; +/** + * Model class representing a chat message. + */ public class Message { private Long id; private Long conversationId; diff --git a/android/app/src/main/java/com/example/petstoremobile/models/Sale.java b/android/app/src/main/java/com/example/petstoremobile/models/Sale.java index ce305d58..c67126e1 100644 --- a/android/app/src/main/java/com/example/petstoremobile/models/Sale.java +++ b/android/app/src/main/java/com/example/petstoremobile/models/Sale.java @@ -1,5 +1,8 @@ package com.example.petstoremobile.models; +/** + * Model class representing a sale transaction. + */ public class Sale { private int saleId; private String saleDate; diff --git a/android/app/src/main/java/com/example/petstoremobile/repositories/ActivityLogRepository.java b/android/app/src/main/java/com/example/petstoremobile/repositories/ActivityLogRepository.java index 6c8acddf..ac890c9a 100644 --- a/android/app/src/main/java/com/example/petstoremobile/repositories/ActivityLogRepository.java +++ b/android/app/src/main/java/com/example/petstoremobile/repositories/ActivityLogRepository.java @@ -11,6 +11,9 @@ import java.util.List; import javax.inject.Inject; import javax.inject.Singleton; +/** + * Repository class for retrieving activity logs from the ActivityLogApi. + */ @Singleton public class ActivityLogRepository extends BaseRepository { private final ActivityLogApi activityLogApi; @@ -21,6 +24,9 @@ public class ActivityLogRepository extends BaseRepository { this.activityLogApi = activityLogApi; } + /** + * Retrieves a list of activity logs with optional filtering. + */ public LiveData>> getActivityLogs(int limit, Long storeId, String role, String search, String startDate, String endDate) { return executeCall(activityLogApi.getActivityLogs(limit, storeId, role, search, startDate, endDate)); } diff --git a/android/app/src/main/java/com/example/petstoremobile/repositories/AdoptionRepository.java b/android/app/src/main/java/com/example/petstoremobile/repositories/AdoptionRepository.java index 8758357a..fd9e5e3c 100644 --- a/android/app/src/main/java/com/example/petstoremobile/repositories/AdoptionRepository.java +++ b/android/app/src/main/java/com/example/petstoremobile/repositories/AdoptionRepository.java @@ -11,6 +11,9 @@ import com.example.petstoremobile.utils.Resource; import javax.inject.Inject; import javax.inject.Singleton; +/** + * Repository class for managing adoption data through the AdoptionApi. + */ @Singleton public class AdoptionRepository extends BaseRepository { private final AdoptionApi adoptionApi; diff --git a/android/app/src/main/java/com/example/petstoremobile/repositories/AppointmentRepository.java b/android/app/src/main/java/com/example/petstoremobile/repositories/AppointmentRepository.java index 6c2c4cf8..3f20ff3e 100644 --- a/android/app/src/main/java/com/example/petstoremobile/repositories/AppointmentRepository.java +++ b/android/app/src/main/java/com/example/petstoremobile/repositories/AppointmentRepository.java @@ -11,6 +11,9 @@ import com.example.petstoremobile.utils.Resource; import javax.inject.Inject; import javax.inject.Singleton; +/** + * Repository class for managing service appointments. + */ @Singleton public class AppointmentRepository extends BaseRepository { private final AppointmentApi appointmentApi; diff --git a/android/app/src/main/java/com/example/petstoremobile/repositories/AuthRepository.java b/android/app/src/main/java/com/example/petstoremobile/repositories/AuthRepository.java index 6011bac8..3e8fa71a 100644 --- a/android/app/src/main/java/com/example/petstoremobile/repositories/AuthRepository.java +++ b/android/app/src/main/java/com/example/petstoremobile/repositories/AuthRepository.java @@ -22,6 +22,9 @@ import retrofit2.Call; import retrofit2.Callback; import retrofit2.Response; +/** + * Repository class for handling authentication-related operations. + */ @Singleton public class AuthRepository extends BaseRepository { private final AuthApi authApi; diff --git a/android/app/src/main/java/com/example/petstoremobile/repositories/BaseRepository.java b/android/app/src/main/java/com/example/petstoremobile/repositories/BaseRepository.java index cf98dfe8..f56067f4 100644 --- a/android/app/src/main/java/com/example/petstoremobile/repositories/BaseRepository.java +++ b/android/app/src/main/java/com/example/petstoremobile/repositories/BaseRepository.java @@ -9,7 +9,7 @@ import com.example.petstoremobile.utils.RetrofitUtils; import retrofit2.Call; /** - * Base class for all repositories to provide common functionality for API calls. + * Base repository class providing common functionality for executing API calls and handling responses. */ public abstract class BaseRepository { protected final String TAG; diff --git a/android/app/src/main/java/com/example/petstoremobile/repositories/CategoryRepository.java b/android/app/src/main/java/com/example/petstoremobile/repositories/CategoryRepository.java index 8d11511b..f518615b 100644 --- a/android/app/src/main/java/com/example/petstoremobile/repositories/CategoryRepository.java +++ b/android/app/src/main/java/com/example/petstoremobile/repositories/CategoryRepository.java @@ -10,6 +10,9 @@ import com.example.petstoremobile.utils.Resource; import javax.inject.Inject; import javax.inject.Singleton; +/** + * Repository class for managing product and service categories. + */ @Singleton public class CategoryRepository extends BaseRepository { private final CategoryApi categoryApi; diff --git a/android/app/src/main/java/com/example/petstoremobile/repositories/ChatRepository.java b/android/app/src/main/java/com/example/petstoremobile/repositories/ChatRepository.java index ec8e32b6..4e5f3ada 100644 --- a/android/app/src/main/java/com/example/petstoremobile/repositories/ChatRepository.java +++ b/android/app/src/main/java/com/example/petstoremobile/repositories/ChatRepository.java @@ -23,7 +23,7 @@ import okhttp3.RequestBody; import okhttp3.ResponseBody; /** - * Repository for handling chat-related data operations. + * Repository class for managing chat messages and conversations. */ @Singleton public class ChatRepository extends BaseRepository { diff --git a/android/app/src/main/java/com/example/petstoremobile/repositories/CouponRepository.java b/android/app/src/main/java/com/example/petstoremobile/repositories/CouponRepository.java index f97d1ca0..83f2289f 100644 --- a/android/app/src/main/java/com/example/petstoremobile/repositories/CouponRepository.java +++ b/android/app/src/main/java/com/example/petstoremobile/repositories/CouponRepository.java @@ -12,6 +12,9 @@ import java.util.List; import javax.inject.Inject; import javax.inject.Singleton; +/** + * Repository class for managing coupon data. + */ @Singleton public class CouponRepository extends BaseRepository { private final CouponApi couponApi; diff --git a/android/app/src/main/java/com/example/petstoremobile/repositories/CustomerRepository.java b/android/app/src/main/java/com/example/petstoremobile/repositories/CustomerRepository.java index 65c9a79d..6067b625 100644 --- a/android/app/src/main/java/com/example/petstoremobile/repositories/CustomerRepository.java +++ b/android/app/src/main/java/com/example/petstoremobile/repositories/CustomerRepository.java @@ -13,6 +13,9 @@ import java.util.List; import javax.inject.Inject; import javax.inject.Singleton; +/** + * Repository class for managing customer information. + */ @Singleton public class CustomerRepository extends BaseRepository { private final CustomerApi customerApi; diff --git a/android/app/src/main/java/com/example/petstoremobile/repositories/EmployeeRepository.java b/android/app/src/main/java/com/example/petstoremobile/repositories/EmployeeRepository.java index b6ddcc9c..745936e6 100644 --- a/android/app/src/main/java/com/example/petstoremobile/repositories/EmployeeRepository.java +++ b/android/app/src/main/java/com/example/petstoremobile/repositories/EmployeeRepository.java @@ -10,6 +10,9 @@ import com.example.petstoremobile.utils.Resource; import javax.inject.Inject; import javax.inject.Singleton; +/** + * Repository class for managing employee data and roles. + */ @Singleton public class EmployeeRepository extends BaseRepository { private final EmployeeApi employeeApi; diff --git a/android/app/src/main/java/com/example/petstoremobile/repositories/InventoryRepository.java b/android/app/src/main/java/com/example/petstoremobile/repositories/InventoryRepository.java index 94526d25..83e8b9c1 100644 --- a/android/app/src/main/java/com/example/petstoremobile/repositories/InventoryRepository.java +++ b/android/app/src/main/java/com/example/petstoremobile/repositories/InventoryRepository.java @@ -11,6 +11,9 @@ import com.example.petstoremobile.utils.Resource; import javax.inject.Inject; import javax.inject.Singleton; +/** + * Repository class for managing inventory and stock levels. + */ @Singleton public class InventoryRepository extends BaseRepository { private final InventoryApi inventoryApi; diff --git a/android/app/src/main/java/com/example/petstoremobile/repositories/PetRepository.java b/android/app/src/main/java/com/example/petstoremobile/repositories/PetRepository.java index 11bb9ff1..f035fa92 100644 --- a/android/app/src/main/java/com/example/petstoremobile/repositories/PetRepository.java +++ b/android/app/src/main/java/com/example/petstoremobile/repositories/PetRepository.java @@ -16,6 +16,9 @@ import javax.inject.Singleton; import okhttp3.MultipartBody; +/** + * Repository class for managing pet data through the PetApi. + */ @Singleton public class PetRepository extends BaseRepository { private final PetApi petApi; diff --git a/android/app/src/main/java/com/example/petstoremobile/repositories/ProductRepository.java b/android/app/src/main/java/com/example/petstoremobile/repositories/ProductRepository.java index 636e1430..1fca4df1 100644 --- a/android/app/src/main/java/com/example/petstoremobile/repositories/ProductRepository.java +++ b/android/app/src/main/java/com/example/petstoremobile/repositories/ProductRepository.java @@ -15,6 +15,9 @@ import javax.inject.Singleton; import okhttp3.MultipartBody; +/** + * Repository class for managing product information and inventory levels. + */ @Singleton public class ProductRepository extends BaseRepository { private final ProductApi productApi; diff --git a/android/app/src/main/java/com/example/petstoremobile/repositories/ProductSupplierRepository.java b/android/app/src/main/java/com/example/petstoremobile/repositories/ProductSupplierRepository.java index 9b2f8df3..41d0393f 100644 --- a/android/app/src/main/java/com/example/petstoremobile/repositories/ProductSupplierRepository.java +++ b/android/app/src/main/java/com/example/petstoremobile/repositories/ProductSupplierRepository.java @@ -11,6 +11,9 @@ import com.example.petstoremobile.utils.Resource; import javax.inject.Inject; import javax.inject.Singleton; +/** + * Repository class for managing relationships between products and their suppliers. + */ @Singleton public class ProductSupplierRepository extends BaseRepository { private final ProductSupplierApi api; diff --git a/android/app/src/main/java/com/example/petstoremobile/repositories/PurchaseOrderRepository.java b/android/app/src/main/java/com/example/petstoremobile/repositories/PurchaseOrderRepository.java index dd9bd637..70537ade 100644 --- a/android/app/src/main/java/com/example/petstoremobile/repositories/PurchaseOrderRepository.java +++ b/android/app/src/main/java/com/example/petstoremobile/repositories/PurchaseOrderRepository.java @@ -10,6 +10,9 @@ import com.example.petstoremobile.utils.Resource; import javax.inject.Inject; import javax.inject.Singleton; +/** + * Repository class for managing purchase orders with suppliers. + */ @Singleton public class PurchaseOrderRepository extends BaseRepository { private final PurchaseOrderApi purchaseOrderApi; diff --git a/android/app/src/main/java/com/example/petstoremobile/repositories/SaleRepository.java b/android/app/src/main/java/com/example/petstoremobile/repositories/SaleRepository.java index 182a7f0e..4fb697a0 100644 --- a/android/app/src/main/java/com/example/petstoremobile/repositories/SaleRepository.java +++ b/android/app/src/main/java/com/example/petstoremobile/repositories/SaleRepository.java @@ -10,6 +10,9 @@ import com.example.petstoremobile.utils.Resource; import javax.inject.Inject; import javax.inject.Singleton; +/** + * Repository class for managing sale transactions and refund data. + */ @Singleton public class SaleRepository extends BaseRepository { private final SaleApi saleApi; diff --git a/android/app/src/main/java/com/example/petstoremobile/repositories/ServiceRepository.java b/android/app/src/main/java/com/example/petstoremobile/repositories/ServiceRepository.java index bd5f3ebc..98e8b457 100644 --- a/android/app/src/main/java/com/example/petstoremobile/repositories/ServiceRepository.java +++ b/android/app/src/main/java/com/example/petstoremobile/repositories/ServiceRepository.java @@ -11,6 +11,9 @@ import com.example.petstoremobile.utils.Resource; import javax.inject.Inject; import javax.inject.Singleton; +/** + * Repository class for managing pet service offerings. + */ @Singleton public class ServiceRepository extends BaseRepository { private final ServiceApi serviceApi; diff --git a/android/app/src/main/java/com/example/petstoremobile/repositories/StoreRepository.java b/android/app/src/main/java/com/example/petstoremobile/repositories/StoreRepository.java index 0df93ab1..dca03260 100644 --- a/android/app/src/main/java/com/example/petstoremobile/repositories/StoreRepository.java +++ b/android/app/src/main/java/com/example/petstoremobile/repositories/StoreRepository.java @@ -13,6 +13,9 @@ import java.util.List; import javax.inject.Inject; import javax.inject.Singleton; +/** + * Repository class for retrieving store-related information. + */ @Singleton public class StoreRepository extends BaseRepository { private final StoreApi storeApi; diff --git a/android/app/src/main/java/com/example/petstoremobile/repositories/SupplierRepository.java b/android/app/src/main/java/com/example/petstoremobile/repositories/SupplierRepository.java index 7aef86a2..bfdf9e39 100644 --- a/android/app/src/main/java/com/example/petstoremobile/repositories/SupplierRepository.java +++ b/android/app/src/main/java/com/example/petstoremobile/repositories/SupplierRepository.java @@ -11,6 +11,9 @@ import com.example.petstoremobile.utils.Resource; import javax.inject.Inject; import javax.inject.Singleton; +/** + * Repository class for managing supplier data. + */ @Singleton public class SupplierRepository extends BaseRepository { private final SupplierApi supplierApi; diff --git a/android/app/src/main/java/com/example/petstoremobile/repositories/UserRepository.java b/android/app/src/main/java/com/example/petstoremobile/repositories/UserRepository.java index 0ed9ced9..bfa9cc23 100644 --- a/android/app/src/main/java/com/example/petstoremobile/repositories/UserRepository.java +++ b/android/app/src/main/java/com/example/petstoremobile/repositories/UserRepository.java @@ -10,6 +10,9 @@ import com.example.petstoremobile.utils.Resource; import javax.inject.Inject; import javax.inject.Singleton; +/** + * Repository class for managing user profile and account data. + */ @Singleton public class UserRepository extends BaseRepository { private final UserApi userApi; diff --git a/android/app/src/main/java/com/example/petstoremobile/services/ChatNotificationService.java b/android/app/src/main/java/com/example/petstoremobile/services/ChatNotificationService.java index 90113cac..46fc5f4d 100644 --- a/android/app/src/main/java/com/example/petstoremobile/services/ChatNotificationService.java +++ b/android/app/src/main/java/com/example/petstoremobile/services/ChatNotificationService.java @@ -30,7 +30,9 @@ import retrofit2.Call; import retrofit2.Callback; import retrofit2.Response; -// Service to receive notifications when a new conversation is created +/** + * Service to receive and display notifications when a new chat conversation or message is created. + */ @AndroidEntryPoint public class ChatNotificationService extends Service { private static final String TAG = "ChatNotificationService"; diff --git a/android/app/src/main/java/com/example/petstoremobile/utils/EventDecorator.java b/android/app/src/main/java/com/example/petstoremobile/utils/EventDecorator.java index b58f38d4..4f3e62ad 100644 --- a/android/app/src/main/java/com/example/petstoremobile/utils/EventDecorator.java +++ b/android/app/src/main/java/com/example/petstoremobile/utils/EventDecorator.java @@ -8,11 +8,17 @@ import com.prolificinteractive.materialcalendarview.spans.DotSpan; import java.util.Collection; import java.util.HashSet; +/** + * Decorator for MaterialCalendarView to highlight specific dates with a colored dot. + */ public class EventDecorator implements DayViewDecorator { private final int color; private final HashSet dates; + /** + * Initializes the decorator with a color and a collection of dates to highlight. + */ public EventDecorator(int color, Collection dates) { this.color = color; this.dates = new HashSet<>(dates); diff --git a/android/app/src/main/java/com/example/petstoremobile/utils/FileUtils.java b/android/app/src/main/java/com/example/petstoremobile/utils/FileUtils.java index bf45f4f8..174b23f5 100644 --- a/android/app/src/main/java/com/example/petstoremobile/utils/FileUtils.java +++ b/android/app/src/main/java/com/example/petstoremobile/utils/FileUtils.java @@ -8,7 +8,14 @@ import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; +/** + * Utility class for file operations, particularly handling Uris from the Android content system. + */ public class FileUtils { + /** + * Creates a temporary file in the cache directory from a given Uri. + * This allows the app to work with a local file path instead of a content stream. + */ public static File getFileFromUri(Context context, Uri uri) { try { if ("content".equals(uri.getScheme())) { @@ -48,6 +55,9 @@ public class FileUtils { } } + /** + * Retrieves the display name of a file from its Uri. + */ public static String getFileName(Context context, Uri uri) { String result = null; if (uri.getScheme().equals("content")) { diff --git a/android/app/src/main/java/com/example/petstoremobile/utils/SelectionHelper.java b/android/app/src/main/java/com/example/petstoremobile/utils/SelectionHelper.java index 197cb557..f651c25a 100644 --- a/android/app/src/main/java/com/example/petstoremobile/utils/SelectionHelper.java +++ b/android/app/src/main/java/com/example/petstoremobile/utils/SelectionHelper.java @@ -5,7 +5,7 @@ import java.util.List; /** * Helper class to manage selection state in Adapters for bulk operations. - * Uses String keys to support both simple Long IDs and composite keys (e.g., "id1-id2"). + * Uses String keys to support both Long IDs and composite keys. */ public class SelectionHelper { @@ -13,15 +13,32 @@ public class SelectionHelper { private boolean selectionMode = false; private final SelectionListener listener; + /** + * Listener interface to observe selection state changes. + */ public interface SelectionListener { + /** + * Called when the number of selected items changes. + */ void onSelectionChanged(int count); + + /** + * Called when selection mode is enabled or disabled. + */ void onSelectionModeToggle(boolean selectionMode); } + /** + * Initializes the helper with a listener. + */ public SelectionHelper(SelectionListener listener) { this.listener = listener; } + /** + * Toggles the selection state of a specific key. + * Automatically exits selection mode if the last item is deselected. + */ public void toggleSelection(String key) { if (key == null) return; @@ -39,6 +56,9 @@ public class SelectionHelper { } } + /** + * Enters selection mode and selects the specified key. + */ public void startSelection(String key) { if (key == null) return; selectionMode = true; @@ -47,18 +67,30 @@ public class SelectionHelper { listener.onSelectionModeToggle(true); } + /** + * Checks if a specific key is currently selected. + */ public boolean isSelected(String key) { return selectedKeys.contains(key); } + /** + * Checks if the helper is currently in selection mode. + */ public boolean isInSelectionMode() { return selectionMode; } + /** + * Returns a copy of the list of currently selected keys. + */ public List getSelectedKeys() { return new ArrayList<>(selectedKeys); } + /** + * Clears all selections and exits selection mode. + */ public void clearSelection() { selectedKeys.clear(); selectionMode = false; diff --git a/android/app/src/main/java/com/example/petstoremobile/utils/SpinnerUtils.java b/android/app/src/main/java/com/example/petstoremobile/utils/SpinnerUtils.java index de1e6304..2273b227 100644 --- a/android/app/src/main/java/com/example/petstoremobile/utils/SpinnerUtils.java +++ b/android/app/src/main/java/com/example/petstoremobile/utils/SpinnerUtils.java @@ -22,7 +22,7 @@ import java.util.function.Function; public class SpinnerUtils { /** - * Populates a spinner with a list of items and handles pre-selection. + * Populates a spinner with generic data and handles pre-selection based on an ID. */ public static void populateSpinner(Context context, Spinner spinner, List data, Function nameExtractor, String defaultText, @@ -31,7 +31,7 @@ public class SpinnerUtils { } /** - * Populates a spinner with white text (for dark backgrounds). + * Populates a spinner with white text, suitable for dark backgrounds or overlays. */ public static void populateWhiteSpinner(Context context, Spinner spinner, List data, Function nameExtractor, String defaultText, @@ -39,6 +39,9 @@ public class SpinnerUtils { populateSpinnerWithAdapter(context, spinner, data, nameExtractor, defaultText, preselectedId, idExtractor, true); } + /** + * Internal helper to populate a spinner with the appropriate adapter and handle pre-selection. + */ private static void populateSpinnerWithAdapter(Context context, Spinner spinner, List data, Function nameExtractor, String defaultText, Long preselectedId, Function idExtractor, diff --git a/android/app/src/main/java/com/example/petstoremobile/viewmodels/ActivityLogListViewModel.java b/android/app/src/main/java/com/example/petstoremobile/viewmodels/ActivityLogListViewModel.java index d944de83..453ddd3b 100644 --- a/android/app/src/main/java/com/example/petstoremobile/viewmodels/ActivityLogListViewModel.java +++ b/android/app/src/main/java/com/example/petstoremobile/viewmodels/ActivityLogListViewModel.java @@ -44,16 +44,37 @@ public class ActivityLogListViewModel extends ViewModel { this.storeRepository = storeRepository; } + /** + * Returns the LiveData for the list of activity logs. + */ public LiveData> getLogs() { return logs; } + + /** + * Returns the LiveData for the store dropdown options. + */ public LiveData> getStoreOptions() { return storeOptions; } + + /** + * Returns the LiveData for the loading state. + */ public LiveData getIsLoading() { return isLoading; } + + /** + * Checks if the last page of logs has been reached. + */ public boolean isLastPage() { return isLastPage; } + /** + * Loads initial data for stores and logs. + */ public void loadInitialData() { loadStores(); loadLogs(true); } + /** + * Loads store options for filtering. + */ private void loadStores() { observeOnce(storeRepository.getStoreDropdowns(), resource -> { if (resource != null && resource.status == Resource.Status.SUCCESS && resource.data != null) { @@ -62,6 +83,9 @@ public class ActivityLogListViewModel extends ViewModel { }); } + /** + * Loads activity logs from the repository with current filters. + */ public void loadLogs(boolean reset) { if (isLoading.getValue() != null && isLoading.getValue() && !reset) return; @@ -88,21 +112,33 @@ public class ActivityLogListViewModel extends ViewModel { }); } + /** + * Sets the role filter and reloads logs. + */ public void setRoleFilter(String role) { currentRole = "All Roles".equals(role) ? null : role; loadLogs(true); } + /** + * Sets the store filter and reloads logs. + */ public void setStoreFilter(Long storeId) { currentStoreId = storeId; loadLogs(true); } + /** + * Sets the search query and reloads logs. + */ public void setSearchQuery(String query) { currentSearch = (query == null || query.trim().isEmpty()) ? null : query.trim(); loadLogs(true); } + /** + * Sets the date range filter and reloads logs. + */ public void setDateRange(String startDate, String endDate) { currentStartDate = startDate; currentEndDate = endDate; @@ -110,6 +146,9 @@ public class ActivityLogListViewModel extends ViewModel { } + /** + * Observes a LiveData once, removing the observer after the first response. + */ private void observeOnce(LiveData> liveData, Observer> handler) { liveData.observeForever(new Observer>() { @Override diff --git a/android/app/src/main/java/com/example/petstoremobile/viewmodels/AdoptionDetailViewModel.java b/android/app/src/main/java/com/example/petstoremobile/viewmodels/AdoptionDetailViewModel.java index 7416c0fc..c25ce797 100644 --- a/android/app/src/main/java/com/example/petstoremobile/viewmodels/AdoptionDetailViewModel.java +++ b/android/app/src/main/java/com/example/petstoremobile/viewmodels/AdoptionDetailViewModel.java @@ -48,24 +48,39 @@ public class AdoptionDetailViewModel extends ViewModel { this.storeRepository = storeRepository; } + /** + * Sets the adoption ID and initializes the view mode. + */ public void setAdoptionId(long id) { this.adoptionId = id; initMode(id != -1); } + /** + * Returns the current adoption ID. + */ public long getAdoptionId() { return adoptionId; } + /** + * Checks if the fragment is currently in editing mode. + */ public boolean isEditing() { ViewState current = viewState.getValue(); return current != null && current.isEditing; } + /** + * Returns the LiveData for the current view state. + */ public LiveData getViewState() { return viewState; } + /** + * Initializes the view state based on whether the mode is editing or adding. + */ public void initMode(boolean isEditing) { updateViewState(state -> { state.isEditing = isEditing; @@ -94,6 +109,9 @@ public class AdoptionDetailViewModel extends ViewModel { }); } + /** + * Loads initial data for the form spinners. + */ public void loadInitialFormData(boolean isEditing) { // Pets are loaded dynamically based on store selection; no pre-load needed. observeOnce(customerRepository.getCustomerDropdowns(), r -> { @@ -108,6 +126,9 @@ public class AdoptionDetailViewModel extends ViewModel { }); } + /** + * Handles customer selection and updates the view state. + */ public void onCustomerSelected(int position) { List list = customerList.getValue(); Long customerId = (position > 0 && list != null && position <= list.size()) @@ -115,6 +136,9 @@ public class AdoptionDetailViewModel extends ViewModel { updateViewState(state -> state.selectedCustomerId = customerId); } + /** + * Handles store selection, updates the view state, and loads related employees and pets. + */ public void onStoreSelected(int position) { List list = storeList.getValue(); if (position > 0 && list != null && position <= list.size()) { @@ -141,6 +165,9 @@ public class AdoptionDetailViewModel extends ViewModel { } } + /** + * Handles pet selection, updates the view state, and loads the pet's price. + */ public void onPetSelected(int position) { List list = petList.getValue(); if (position > 0 && list != null && position <= list.size()) { @@ -155,6 +182,9 @@ public class AdoptionDetailViewModel extends ViewModel { } } + /** + * Loads available pets for the selected store. + */ private void loadAvailablePetsByStore(Long storeId) { observeOnce(petRepository.getAdoptionPets(storeId), r -> { if (r != null && r.status == Resource.Status.SUCCESS && r.data != null) { @@ -163,6 +193,9 @@ public class AdoptionDetailViewModel extends ViewModel { }); } + /** + * Loads the price for a specific pet. + */ private void loadPetPrice(Long petId) { observeOnce(petRepository.getPetById(petId), r -> { if (r != null && r.status == Resource.Status.SUCCESS && r.data != null) { @@ -181,6 +214,9 @@ public class AdoptionDetailViewModel extends ViewModel { }); } + /** + * Loads employees assigned to a specific store. + */ private void loadEmployeesForStore(Long storeId) { observeOnce(storeRepository.getStoreEmployees(storeId), r -> { if (r != null && r.status == Resource.Status.SUCCESS && r.data != null) { @@ -190,7 +226,7 @@ public class AdoptionDetailViewModel extends ViewModel { } /** - * Called when the date or status changes in the UI. Applies date-based field enabling. + * Called when the date or status changes in the UI. */ public void onDateChanged(String date, String currentStatus) { updateViewState(s -> { @@ -203,7 +239,7 @@ public class AdoptionDetailViewModel extends ViewModel { s.selectedStatus = s.availableStatuses[0]; } - if (!s.isEditing) return; // add mode: field enabling handled separately + if (!s.isEditing) return; boolean isPast = DateTimeUtils.isDateBeforeToday(date); if (isPast) { @@ -222,6 +258,9 @@ public class AdoptionDetailViewModel extends ViewModel { }); } + /** + * Calculates available statuses based on the date and mode. + */ private String[] calculateAvailableStatuses(boolean isEditing, String date) { if (!isEditing) return new String[]{"Pending"}; if (date == null || date.isEmpty()) return new String[]{}; @@ -236,9 +275,11 @@ public class AdoptionDetailViewModel extends ViewModel { s.isPetEnabled = enabled; s.isEmployeeEnabled = enabled; s.isDateEnabled = enabled; - // fee never editable } + /** + * Fetches adoption details from the repository. + */ public LiveData> loadAdoption() { MutableLiveData> result = new MutableLiveData<>(); observeOnce(adoptionRepository.getAdoptionById(adoptionId), resource -> { @@ -292,6 +333,9 @@ public class AdoptionDetailViewModel extends ViewModel { return result; } + /** + * Saves or updates the adoption record. + */ public LiveData> saveAdoption(AdoptionDTO dto) { if (isEditing()) { return adoptionRepository.updateAdoption(adoptionId, dto); @@ -299,17 +343,41 @@ public class AdoptionDetailViewModel extends ViewModel { return adoptionRepository.createAdoption(dto); } + /** + * Deletes the current adoption record. + */ public LiveData> deleteAdoption() { return adoptionRepository.deleteAdoption(adoptionId); } + /** + * Returns the LiveData for the pet dropdown list. + */ public LiveData> getPetList() { return petList; } + + /** + * Returns the LiveData for the customer dropdown list. + */ public LiveData> getCustomerList() { return customerList; } + + /** + * Returns the LiveData for the store dropdown list. + */ public LiveData> getStoreList() { return storeList; } + + /** + * Returns the LiveData for the employee dropdown list. + */ public LiveData> getEmployeeList() { return employeeList; } + /** + * Updates the employee list. + */ public void setEmployeeList(List list) { employeeList.setValue(list); } + /** + * Helper to update the view state atomically. + */ private void updateViewState(Action action) { ViewState current = viewState.getValue(); if (current != null) { diff --git a/android/app/src/main/java/com/example/petstoremobile/viewmodels/AdoptionListViewModel.java b/android/app/src/main/java/com/example/petstoremobile/viewmodels/AdoptionListViewModel.java index 005198d1..dbfc262b 100644 --- a/android/app/src/main/java/com/example/petstoremobile/viewmodels/AdoptionListViewModel.java +++ b/android/app/src/main/java/com/example/petstoremobile/viewmodels/AdoptionListViewModel.java @@ -39,11 +39,29 @@ public class AdoptionListViewModel extends ViewModel { this.storeRepository = storeRepository; } + /** + * Returns the LiveData for the list of adoptions. + */ public LiveData> getAdoptions() { return adoptions; } + + /** + * Returns the LiveData for the list of stores for filtering. + */ public LiveData> getStores() { return stores; } + + /** + * Returns the LiveData for the loading state. + */ public LiveData getIsLoading() { return isLoading; } + + /** + * Checks if the last page of adoptions has been reached. + */ public boolean isLastPage() { return isLastPage; } + /** + * Loads adoptions from the repository with the specified filters. + */ public void loadAdoptions(boolean reset, String query, String status, Long storeId, String date, Long employeeId) { if (isLoading.getValue() != null && isLoading.getValue() && !reset) return; @@ -73,6 +91,9 @@ public class AdoptionListViewModel extends ViewModel { }); } + /** + * Loads the list of stores for filtering options. + */ public void loadStores() { observeOnce(storeRepository.getAllStores(0, 100), resource -> { if (resource != null && resource.status == Resource.Status.SUCCESS && resource.data != null) { @@ -93,6 +114,9 @@ public class AdoptionListViewModel extends ViewModel { }); } + /** + * Deletes multiple adoptions by their IDs. + */ public LiveData> bulkDeleteAdoptions(List ids) { return adoptionRepository.bulkDeleteAdoptions(new BulkDeleteRequest(ids)); } diff --git a/android/app/src/main/java/com/example/petstoremobile/viewmodels/AnalyticsViewModel.java b/android/app/src/main/java/com/example/petstoremobile/viewmodels/AnalyticsViewModel.java index 4a9b94d9..95c8979f 100644 --- a/android/app/src/main/java/com/example/petstoremobile/viewmodels/AnalyticsViewModel.java +++ b/android/app/src/main/java/com/example/petstoremobile/viewmodels/AnalyticsViewModel.java @@ -28,6 +28,9 @@ import javax.inject.Inject; import dagger.hilt.android.lifecycle.HiltViewModel; +/** + * ViewModel for retrieving and providing data for the analytics dashboard. + */ @HiltViewModel public class AnalyticsViewModel extends ViewModel { private final SaleRepository saleRepository; @@ -50,12 +53,34 @@ public class AnalyticsViewModel extends ViewModel { this.tokenManager = tokenManager; } + /** + * Returns the LiveData for the analytics data. + */ public LiveData getAnalyticsData() { return analyticsData; } + + /** + * Returns the LiveData for the loading state. + */ public LiveData getIsLoading() { return isLoading; } + + /** + * Returns the LiveData for error messages. + */ public LiveData getErrorMessage() { return errorMessage; } + + /** + * Returns the LiveData for available payment method filters. + */ public LiveData> getAvailablePaymentMethods() { return availablePaymentMethods; } + + /** + * Returns the LiveData for available store filters. + */ public LiveData> getAvailableStores() { return availableStores; } + /** + * Triggers loading of analytics data with current filters. + */ public void loadAnalytics() { isLoading.setValue(true); errorMessage.setValue(null); @@ -75,35 +100,56 @@ public class AnalyticsViewModel extends ViewModel { }); } + /** + * Applies a new filter state and re-computes analytics. + */ public void applyFilter(FilterState filter) { currentFilter = filter; applyCurrentFilter(); } + /** + * Resets filters to default values and reset analytics. + */ public void resetFilter() { currentFilter = new FilterState(); storeFilter = "All Stores"; applyCurrentFilter(); } + /** + * Sets the view mode + */ public void setViewMode(String mode) { viewMode = mode; applyCurrentFilter(); } + /** + * Returns the current view mode. + */ public String getViewMode() { return viewMode; } + /** + * Sets the store filter + */ public void setStoreFilter(String store) { storeFilter = (store != null && !store.isEmpty()) ? store : "All Stores"; applyCurrentFilter(); } + /** + * Returns the current store filter. + */ public String getStoreFilter() { return storeFilter; } + /** + * Applies the current filters + */ private void applyCurrentFilter() { List salesForMode; if (viewMode.equals("mine")) { @@ -124,6 +170,9 @@ public class AnalyticsViewModel extends ViewModel { computeAnalytics(filtered, currentFilter); } + /** + * Extracts unique store names from the cached sales data for filtering. + */ private void deriveStores() { java.util.Set stores = new java.util.TreeSet<>(); for (SaleDTO s : cachedSales) { @@ -137,6 +186,9 @@ public class AnalyticsViewModel extends ViewModel { availableStores.setValue(result); } + /** + * Extracts unique payment methods from the cached sales data for filtering. + */ private void derivePaymentMethods() { java.util.Set methods = new java.util.TreeSet<>(); for (SaleDTO s : cachedSales) { @@ -150,6 +202,9 @@ public class AnalyticsViewModel extends ViewModel { availablePaymentMethods.setValue(result); } + /** + * Filters a list of sales based on date range and payment method. + */ private List filterSales(List sales, FilterState filter) { List result = new ArrayList<>(); for (SaleDTO s : sales) { @@ -165,6 +220,9 @@ public class AnalyticsViewModel extends ViewModel { return result; } + /** + * Computesanalytics data from a filtered list of sales. + */ private void computeAnalytics(List sales, FilterState filter) { List regularSales = new ArrayList<>(); for (SaleDTO s : sales) { @@ -258,6 +316,9 @@ public class AnalyticsViewModel extends ViewModel { analyticsData.setValue(data); } + /** + * Returns a date string for the specified offset from today. + */ private String todayString(int offsetDays) { Calendar c = Calendar.getInstance(); c.add(Calendar.DAY_OF_YEAR, offsetDays); @@ -265,6 +326,9 @@ public class AnalyticsViewModel extends ViewModel { c.get(Calendar.YEAR), c.get(Calendar.MONTH) + 1, c.get(Calendar.DAY_OF_MONTH)); } + /** + * Shifts a date string by a specified number of days. + */ private String shiftDate(String date, int offsetDays) { try { String[] p = date.split("-"); @@ -278,6 +342,9 @@ public class AnalyticsViewModel extends ViewModel { } } + /** + * Generates a list of date strings between the start and end dates. + */ private List buildDateRange(String start, String end, int maxDays) { List dates = new ArrayList<>(); try { @@ -298,6 +365,9 @@ public class AnalyticsViewModel extends ViewModel { return dates; } + /** + * Builds a title for the daily revenue chart based on the date range. + */ private String buildDailyTitle(FilterState filter, String rangeStart, String rangeEnd) { if (filter.startDate.isEmpty() && filter.endDate.isEmpty()) return "Daily Revenue (Last 7 Days)"; String s = rangeStart.length() >= 10 ? rangeStart.substring(5) : rangeStart; @@ -305,6 +375,9 @@ public class AnalyticsViewModel extends ViewModel { return "Daily Revenue (" + s + " – " + e + ")"; } + /** + * Observes a LiveData once, removing the observer after the first non-loading response. + */ private void observeOnce(LiveData> liveData, Observer> handler) { liveData.observeForever(new Observer>() { @Override diff --git a/android/app/src/main/java/com/example/petstoremobile/viewmodels/AppointmentDetailViewModel.java b/android/app/src/main/java/com/example/petstoremobile/viewmodels/AppointmentDetailViewModel.java index b229c3a0..c96e21de 100644 --- a/android/app/src/main/java/com/example/petstoremobile/viewmodels/AppointmentDetailViewModel.java +++ b/android/app/src/main/java/com/example/petstoremobile/viewmodels/AppointmentDetailViewModel.java @@ -387,7 +387,9 @@ public class AppointmentDetailViewModel extends ViewModel { void run(T t); } - /** Observes a LiveData once, removing the observer after the first non-loading response. */ + /** + * Observes a LiveData once, removing the observer after the first non-loading response. + */ private void observeOnce(LiveData> liveData, Observer> handler) { liveData.observeForever(new Observer>() { @Override diff --git a/android/app/src/main/java/com/example/petstoremobile/viewmodels/AppointmentListViewModel.java b/android/app/src/main/java/com/example/petstoremobile/viewmodels/AppointmentListViewModel.java index 19924349..30aa2511 100644 --- a/android/app/src/main/java/com/example/petstoremobile/viewmodels/AppointmentListViewModel.java +++ b/android/app/src/main/java/com/example/petstoremobile/viewmodels/AppointmentListViewModel.java @@ -39,11 +39,29 @@ public class AppointmentListViewModel extends ViewModel { this.storeRepository = storeRepository; } + /** + * Returns the LiveData for the list of appointments. + */ public LiveData> getAppointments() { return appointments; } + + /** + * Returns the LiveData for the list of stores for filtering. + */ public LiveData> getStores() { return stores; } + + /** + * Returns the LiveData for the loading state. + */ public LiveData getIsLoading() { return isLoading; } + + /** + * Checks if the last page of appointments has been reached. + */ public boolean isLastPage() { return isLastPage; } + /** + * Loads appointments from the repository with the specified filters. + */ public void loadAppointments(boolean reset, String query, String status, Long storeId, String date, Long employeeId) { if (isLoading.getValue() != null && isLoading.getValue() && !reset) return; @@ -71,6 +89,9 @@ public class AppointmentListViewModel extends ViewModel { }); } + /** + * Loads the list of stores for filtering options. + */ public void loadStores() { observeOnce(storeRepository.getAllStores(0, 100), resource -> { if (resource != null && resource.status == Resource.Status.SUCCESS && resource.data != null) { @@ -91,6 +112,9 @@ public class AppointmentListViewModel extends ViewModel { }); } + /** + * Deletes multiple appointments by their IDs. + */ public LiveData> bulkDeleteAppointments(List ids) { return appointmentRepository.bulkDeleteAppointments(new BulkDeleteRequest(ids)); } diff --git a/android/app/src/main/java/com/example/petstoremobile/viewmodels/AuthViewModel.java b/android/app/src/main/java/com/example/petstoremobile/viewmodels/AuthViewModel.java index 36e437bb..cc05eb3e 100644 --- a/android/app/src/main/java/com/example/petstoremobile/viewmodels/AuthViewModel.java +++ b/android/app/src/main/java/com/example/petstoremobile/viewmodels/AuthViewModel.java @@ -16,6 +16,9 @@ import javax.inject.Inject; import dagger.hilt.android.lifecycle.HiltViewModel; import okhttp3.MultipartBody; +/** + * ViewModel for managing user authentication and profile data. + */ @HiltViewModel public class AuthViewModel extends ViewModel { private final AuthRepository repository; @@ -26,42 +29,42 @@ public class AuthViewModel extends ViewModel { } /** - * Authenticates a user with username and password. + * Attempts to log in the user with the provided credentials. */ public LiveData> login(String username, String password) { return repository.login(new AuthDTO.LoginRequest(username, password)); } /** - * Retrieves the profile information of the currently authenticated user. + * Retrieves the current user's profile information. */ public LiveData> getMe() { return repository.getMe(); } /** - * Updates the profile information of the current user. + * Updates the current user's profile information. */ public LiveData> updateMe(Map updates) { return repository.updateMe(updates); } /** - * Uploads a new avatar image for the current user. + * Uploads a new avatar for the current user. */ public LiveData> uploadAvatar(MultipartBody.Part avatar) { return repository.uploadAvatar(avatar); } /** - * Deletes the avatar image of the current user. + * Deletes the current user's avatar. */ public LiveData> deleteAvatar() { return repository.deleteAvatar(); } /** - * Logs out the current user by clearing stored credentials. + * Logs out the user by clearing the session. */ public void logout() { repository.logout(); diff --git a/android/app/src/main/java/com/example/petstoremobile/viewmodels/ChatListViewModel.java b/android/app/src/main/java/com/example/petstoremobile/viewmodels/ChatListViewModel.java index 4d14a3b4..0010d227 100644 --- a/android/app/src/main/java/com/example/petstoremobile/viewmodels/ChatListViewModel.java +++ b/android/app/src/main/java/com/example/petstoremobile/viewmodels/ChatListViewModel.java @@ -29,6 +29,9 @@ import okhttp3.MultipartBody; import okhttp3.RequestBody; import okhttp3.ResponseBody; +/** + * ViewModel for managing the list of chat conversations and real-time message updates. + */ @HiltViewModel public class ChatListViewModel extends ViewModel { private final ChatRepository chatRepository; @@ -48,19 +51,43 @@ public class ChatListViewModel extends ViewModel { this.customerRepository = customerRepository; } + /** + * Returns the LiveData for the list of active chats. + */ public LiveData> getActiveChats() { return activeChats; } + + /** + * Returns the LiveData for the list of closed chats. + */ public LiveData> getClosedChats() { return closedChats; } + + /** + * Returns the LiveData for the list of messages in the current conversation. + */ public LiveData> getMessageList() { return messageList; } + + /** + * Returns the LiveData for the loading state. + */ public LiveData getIsLoading() { return isLoading; } + /** + * Returns the ID of the last active conversation. + */ public Long getLastActiveConversationId() { return lastActiveConversationId; } + /** + * Sets the ID of the last active conversation. + */ public void setLastActiveConversationId(Long conversationId) { this.lastActiveConversationId = conversationId; } + /** + * Loads the list of customers for name mapping. + */ public void loadCustomers() { isLoading.setValue(true); customerRepository.getAllCustomers(0, 100).observeForever(resource -> { @@ -75,6 +102,9 @@ public class ChatListViewModel extends ViewModel { }); } + /** + * Loads all chat conversations from the repository. + */ public void loadConversations() { isLoading.setValue(true); chatRepository.getAllConversations().observeForever(resource -> { @@ -99,6 +129,9 @@ public class ChatListViewModel extends ViewModel { }); } + /** + * Loads message history for a specific conversation. + */ public void loadMessageHistory(Long conversationId) { isLoading.setValue(true); chatRepository.getMessages(conversationId).observeForever(resource -> { @@ -115,22 +148,37 @@ public class ChatListViewModel extends ViewModel { }); } + /** + * Sends a text message in a specific conversation. + */ public LiveData> sendMessage(Long conversationId, String text) { return chatRepository.sendMessage(conversationId, new SendMessageRequest(text)); } + /** + * Sends a message with an attachment in a specific conversation. + */ public LiveData> sendMessageWithAttachment(Long conversationId, MultipartBody.Part content, MultipartBody.Part attachment) { return chatRepository.sendMessageWithAttachment(conversationId, content, attachment); } + /** + * Downloads an attachment for a specific message. + */ public LiveData> downloadAttachment(Long messageId) { return chatRepository.downloadAttachment(messageId); } + /** + * Closes an active chat conversation. + */ public LiveData> closeConversation(Long conversationId) { return chatRepository.updateConversationStatus(conversationId, new UpdateConversationStatusRequest("CLOSED")); } + /** + * Adds a message to the local list (used for real-time updates). + */ public void addMessageLocally(MessageDTO dto) { List current = new ArrayList<>(messageList.getValue()); if (dto.getId() != null) { @@ -142,6 +190,9 @@ public class ChatListViewModel extends ViewModel { messageList.setValue(current); } + /** + * Updates a conversation's status locally. + */ public void updateConversationLocally(ConversationDTO dto) { updateList(activeChats, dto); updateList(closedChats, dto); @@ -180,6 +231,9 @@ public class ChatListViewModel extends ViewModel { return m; } + /** + * Retrieves a customer's name by their ID. + */ public String getCustomerName(Long customerId) { return customerNames.getOrDefault(customerId, "Customer #" + customerId); } diff --git a/android/app/src/main/java/com/example/petstoremobile/viewmodels/CouponDetailViewModel.java b/android/app/src/main/java/com/example/petstoremobile/viewmodels/CouponDetailViewModel.java index 49f52ef5..93541676 100644 --- a/android/app/src/main/java/com/example/petstoremobile/viewmodels/CouponDetailViewModel.java +++ b/android/app/src/main/java/com/example/petstoremobile/viewmodels/CouponDetailViewModel.java @@ -23,23 +23,38 @@ public class CouponDetailViewModel extends ViewModel { this.repository = repository; } + /** + * Loads the coupon details from the repository. + */ public LiveData> loadCoupon(long id) { return repository.getCouponById(id); } + /** + * Sets the current coupon ID and editing mode. + */ public void setCouponId(long id, boolean isEditing) { this.couponId = id; this.isEditing = isEditing; } + /** + * Returns the current coupon ID. + */ public long getCouponId() { return couponId; } + /** + * Checks if the fragment is in editing mode. + */ public boolean isEditing() { return isEditing; } + /** + * Saves or updates the coupon record. + */ public LiveData> saveCoupon(CouponDTO dto) { if (isEditing && couponId > 0) { return repository.updateCoupon(couponId, dto); @@ -48,6 +63,9 @@ public class CouponDetailViewModel extends ViewModel { } } + /** + * Deletes the current coupon record. + */ public LiveData> deleteCoupon() { return repository.deleteCoupon(couponId); } diff --git a/android/app/src/main/java/com/example/petstoremobile/viewmodels/CouponListViewModel.java b/android/app/src/main/java/com/example/petstoremobile/viewmodels/CouponListViewModel.java index d825b935..eeb47f16 100644 --- a/android/app/src/main/java/com/example/petstoremobile/viewmodels/CouponListViewModel.java +++ b/android/app/src/main/java/com/example/petstoremobile/viewmodels/CouponListViewModel.java @@ -17,6 +17,9 @@ import javax.inject.Inject; import dagger.hilt.android.lifecycle.HiltViewModel; +/** + * ViewModel for managing the list of coupons. + */ @HiltViewModel public class CouponListViewModel extends ViewModel { private final CouponRepository repository; @@ -32,10 +35,24 @@ public class CouponListViewModel extends ViewModel { this.repository = repository; } + /** + * Returns the LiveData for the list of coupons. + */ public LiveData> getCoupons() { return coupons; } + + /** + * Returns the LiveData for the loading state. + */ public LiveData getIsLoading() { return isLoading; } + + /** + * Checks if the last page of coupons has been reached. + */ public boolean isLastPage() { return isLastPage; } + /** + * Loads coupons from the repository with the specified filters. + */ public void loadCoupons(boolean reset, Boolean active, String discountType, String sort) { if (isLoading.getValue() != null && isLoading.getValue() && !reset) return; @@ -75,6 +92,9 @@ public class CouponListViewModel extends ViewModel { }); } + /** + * Deletes multiple coupons by their IDs. + */ public LiveData> bulkDeleteCoupons(List ids) { return repository.bulkDeleteCoupons(ids); } diff --git a/android/app/src/main/java/com/example/petstoremobile/viewmodels/CustomerDetailViewModel.java b/android/app/src/main/java/com/example/petstoremobile/viewmodels/CustomerDetailViewModel.java index 0d0ebfaf..1604c9e8 100644 --- a/android/app/src/main/java/com/example/petstoremobile/viewmodels/CustomerDetailViewModel.java +++ b/android/app/src/main/java/com/example/petstoremobile/viewmodels/CustomerDetailViewModel.java @@ -23,6 +23,9 @@ public class CustomerDetailViewModel extends ViewModel { this.repository = repository; } + /** + * Sets the current customer ID and editing mode. + */ public void setCustomerId(long id, boolean isEditing) { this.customerId = id; this.isEditing = isEditing; @@ -48,6 +51,9 @@ public class CustomerDetailViewModel extends ViewModel { return repository.getCustomerById(id); } + /** + * Saves or updates the customer record. + */ public LiveData> saveCustomer(CustomerDTO dto) { if (isEditing && customerId > 0) { return repository.updateCustomer(customerId, dto); @@ -56,6 +62,9 @@ public class CustomerDetailViewModel extends ViewModel { } } + /** + * Deletes the current customer record. + */ public LiveData> deleteCustomer() { return repository.deleteCustomer(customerId); } diff --git a/android/app/src/main/java/com/example/petstoremobile/viewmodels/CustomerListViewModel.java b/android/app/src/main/java/com/example/petstoremobile/viewmodels/CustomerListViewModel.java index a216c47a..2fd7393b 100644 --- a/android/app/src/main/java/com/example/petstoremobile/viewmodels/CustomerListViewModel.java +++ b/android/app/src/main/java/com/example/petstoremobile/viewmodels/CustomerListViewModel.java @@ -17,6 +17,9 @@ import javax.inject.Inject; import dagger.hilt.android.lifecycle.HiltViewModel; +/** + * ViewModel for managing the list of customers, including local filtering and pagination. + */ @HiltViewModel public class CustomerListViewModel extends ViewModel { private final CustomerRepository repository; @@ -37,10 +40,24 @@ public class CustomerListViewModel extends ViewModel { this.repository = repository; } + /** + * Returns the LiveData for the list of filtered customers. + */ public LiveData> getFilteredCustomers() { return filteredCustomers; } + + /** + * Returns the LiveData for the loading state. + */ public LiveData getIsLoading() { return isLoading; } + + /** + * Checks if the last page of customers has been reached. + */ public boolean isLastPage() { return isLastPage; } + /** + * Loads the full list of customers from the repository. + */ public void loadCustomers(boolean reset) { if (isLoading.getValue() != null && isLoading.getValue() && !reset) return; @@ -69,6 +86,9 @@ public class CustomerListViewModel extends ViewModel { }); } + /** + * Observes a LiveData once, removing the observer after the first non-loading response. + */ private void observeOnce(LiveData> liveData, Observer> handler) { liveData.observeForever(new Observer>() { @Override @@ -81,12 +101,18 @@ public class CustomerListViewModel extends ViewModel { }); } + /** + * Filters the customer list locally based on query and status. + */ public void filter(String query, String status) { this.lastQuery = query; this.lastStatus = status; applyFilter(customers.getValue()); } + /** + * Applies the filters to the full list and updates the filtered LiveData. + */ private void applyFilter(List all) { if (all == null) return; diff --git a/android/app/src/main/java/com/example/petstoremobile/viewmodels/InventoryDetailViewModel.java b/android/app/src/main/java/com/example/petstoremobile/viewmodels/InventoryDetailViewModel.java index c872ea49..3bf33373 100644 --- a/android/app/src/main/java/com/example/petstoremobile/viewmodels/InventoryDetailViewModel.java +++ b/android/app/src/main/java/com/example/petstoremobile/viewmodels/InventoryDetailViewModel.java @@ -39,26 +39,48 @@ public class InventoryDetailViewModel extends ViewModel { this.productRepository = productRepository; } + /** + * Sets the inventory ID and initializes the editing mode. + */ public void setInventoryId(long id) { this.inventoryId = id; this.isEditing = id != -1; } + /** + * Returns the current inventory ID. + */ public long getInventoryId() { return inventoryId; } + + /** + * Checks if the fragment is in editing mode. + */ public boolean isEditing() { return isEditing; } + /** + * Loads the inventory record from the repository. + */ public LiveData> loadInventory() { return inventoryRepository.getInventoryById(inventoryId); } + /** + * Loads store dropdown options. + */ public LiveData>> loadStores() { return storeRepository.getStoreDropdowns(); } + /** + * Loads product dropdown options. + */ public LiveData>> loadProducts() { return productRepository.getProductDropdowns(); } + /** + * Saves or updates the inventory record. + */ public LiveData> saveInventory(InventoryDTO dto) { if (isEditing) { return inventoryRepository.updateInventory(inventoryId, dto); @@ -67,13 +89,30 @@ public class InventoryDetailViewModel extends ViewModel { } } + /** + * Deletes the current inventory record. + */ public LiveData> deleteInventory() { return inventoryRepository.deleteInventory(inventoryId); } + /** + * Updates the store list. + */ public void setStoreList(List list) { storeList.setValue(list); } + + /** + * Returns the LiveData for the store list. + */ public LiveData> getStoreList() { return storeList; } + /** + * Updates the product list. + */ public void setProductList(List list) { productList.setValue(list); } + + /** + * Returns the LiveData for the product list. + */ public LiveData> getProductList() { return productList; } } diff --git a/android/app/src/main/java/com/example/petstoremobile/viewmodels/InventoryListViewModel.java b/android/app/src/main/java/com/example/petstoremobile/viewmodels/InventoryListViewModel.java index 66387983..8e482390 100644 --- a/android/app/src/main/java/com/example/petstoremobile/viewmodels/InventoryListViewModel.java +++ b/android/app/src/main/java/com/example/petstoremobile/viewmodels/InventoryListViewModel.java @@ -39,11 +39,29 @@ public class InventoryListViewModel extends ViewModel { this.storeRepository = storeRepository; } + /** + * Returns the LiveData for the inventory list. + */ public LiveData> getInventory() { return inventory; } + + /** + * Returns the LiveData for the store list for filtering. + */ public LiveData> getStores() { return stores; } + + /** + * Returns the LiveData for the loading state. + */ public LiveData getIsLoading() { return isLoading; } + + /** + * Checks if the last page of inventory has been reached. + */ public boolean isLastPage() { return isLastPage; } + /** + * Loads inventory items from the repository with the specified filters. + */ public void loadInventory(boolean reset, String query, Long storeId) { if (isLoading.getValue() != null && isLoading.getValue() && !reset) return; @@ -69,6 +87,9 @@ public class InventoryListViewModel extends ViewModel { }); } + /** + * Loads the list of stores for filtering options. + */ public void loadStores() { observeOnce(storeRepository.getAllStores(0, 100), resource -> { if (resource != null && resource.status == Resource.Status.SUCCESS && resource.data != null) { @@ -89,6 +110,9 @@ public class InventoryListViewModel extends ViewModel { }); } + /** + * Deletes multiple inventory items by their IDs. + */ public LiveData> bulkDeleteInventory(List ids) { return inventoryRepository.bulkDeleteInventory(new BulkDeleteRequest(ids)); } diff --git a/android/app/src/main/java/com/example/petstoremobile/viewmodels/PetListViewModel.java b/android/app/src/main/java/com/example/petstoremobile/viewmodels/PetListViewModel.java index 89f56d51..5c04e468 100644 --- a/android/app/src/main/java/com/example/petstoremobile/viewmodels/PetListViewModel.java +++ b/android/app/src/main/java/com/example/petstoremobile/viewmodels/PetListViewModel.java @@ -21,6 +21,9 @@ import javax.inject.Inject; import dagger.hilt.android.lifecycle.HiltViewModel; +/** + * ViewModel for managing the list of pets, including filtering and bulk deletion. + */ @HiltViewModel public class PetListViewModel extends ViewModel { private final PetRepository petRepository; @@ -41,12 +44,34 @@ public class PetListViewModel extends ViewModel { this.storeRepository = storeRepository; } + /** + * Returns the LiveData for the list of pets. + */ public LiveData> getPets() { return pets; } + + /** + * Returns the LiveData for the list of stores for filtering. + */ public LiveData> getStores() { return stores; } + + /** + * Returns the LiveData for available species filters. + */ public LiveData> getSpeciesOptions() { return speciesOptions; } + + /** + * Returns the LiveData for the loading state. + */ public LiveData getIsLoading() { return isLoading; } + + /** + * Checks if the last page of pets has been reached. + */ public boolean isLastPage() { return isLastPage; } + /** + * Loads pets from the repository with the specified filters. + */ public void loadPets(boolean reset, String query, String status, String species, Long storeId) { if (isLoading.getValue() != null && isLoading.getValue() && !reset) return; @@ -79,6 +104,9 @@ public class PetListViewModel extends ViewModel { }); } + /** + * Loads the list of available species for filtering. + */ public void loadSpecies() { observeOnce(petRepository.getPetSpeciesDropdowns(), resource -> { if (resource != null && resource.status == Resource.Status.SUCCESS && resource.data != null) { @@ -92,6 +120,9 @@ public class PetListViewModel extends ViewModel { }); } + /** + * Loads the list of stores for filtering options. + */ public void loadStores() { observeOnce(storeRepository.getAllStores(0, 100), resource -> { if (resource != null && resource.status == Resource.Status.SUCCESS && resource.data != null) { @@ -100,6 +131,9 @@ public class PetListViewModel extends ViewModel { }); } + /** + * Observes a LiveData once, removing the observer after the first non-loading response. + */ private void observeOnce(LiveData> liveData, Observer> handler) { liveData.observeForever(new Observer>() { @Override @@ -112,6 +146,9 @@ public class PetListViewModel extends ViewModel { }); } + /** + * Deletes multiple pets by their IDs. + */ public LiveData> bulkDeletePets(List ids) { return petRepository.bulkDeletePets(new BulkDeleteRequest(ids)); } diff --git a/android/app/src/main/java/com/example/petstoremobile/viewmodels/PetProfileViewModel.java b/android/app/src/main/java/com/example/petstoremobile/viewmodels/PetProfileViewModel.java index 1fb75f1c..8366bf63 100644 --- a/android/app/src/main/java/com/example/petstoremobile/viewmodels/PetProfileViewModel.java +++ b/android/app/src/main/java/com/example/petstoremobile/viewmodels/PetProfileViewModel.java @@ -21,14 +21,23 @@ public class PetProfileViewModel extends ViewModel { this.repository = repository; } + /** + * Retrieves a pet's details by its ID. + */ public LiveData> getPetById(Long id) { return repository.getPetById(id); } + /** + * Uploads an image for a specific pet. + */ public LiveData> uploadPetImage(Long id, MultipartBody.Part image) { return repository.uploadPetImage(id, image); } + /** + * Deletes the image for a specific pet. + */ public LiveData> deletePetImage(Long id) { return repository.deletePetImage(id); } diff --git a/android/app/src/main/java/com/example/petstoremobile/viewmodels/ProductDetailViewModel.java b/android/app/src/main/java/com/example/petstoremobile/viewmodels/ProductDetailViewModel.java index c1ac5fdd..3c157dde 100644 --- a/android/app/src/main/java/com/example/petstoremobile/viewmodels/ProductDetailViewModel.java +++ b/android/app/src/main/java/com/example/petstoremobile/viewmodels/ProductDetailViewModel.java @@ -35,27 +35,45 @@ public class ProductDetailViewModel extends ViewModel { this.categoryRepository = categoryRepository; } + /** + * Sets the product ID and initializes the editing mode. + */ public void setProdId(long id) { this.prodId = id; this.isEditing = id != -1; } + /** + * Returns the current product ID. + */ public long getProdId() { return prodId; } + /** + * Checks if the fragment is in editing mode. + */ public boolean isEditing() { return isEditing; } + /** + * Loads product category dropdown options. + */ public LiveData>> loadCategories() { return productRepository.getCategoryDropdowns(); } + /** + * Loads the product details from the repository. + */ public LiveData> loadProduct() { return productRepository.getProductById(prodId); } + /** + * Saves or updates the product record. + */ public LiveData> saveProduct(ProductDTO dto) { if (isEditing) { return productRepository.updateProduct(prodId, dto); @@ -64,22 +82,37 @@ public class ProductDetailViewModel extends ViewModel { } } + /** + * Deletes the current product record. + */ public LiveData> deleteProduct() { return productRepository.deleteProduct(prodId); } + /** + * Uploads an image for the current product. + */ public LiveData> uploadProductImage(MultipartBody.Part image) { return productRepository.uploadProductImage(prodId, image); } + /** + * Deletes the current product's image. + */ public LiveData> deleteProductImage() { return productRepository.deleteProductImage(prodId); } + /** + * Updates the category list. + */ public void setCategoryList(List list) { categoryList.setValue(list); } + /** + * Returns the LiveData for the category list. + */ public LiveData> getCategoryList() { return categoryList; } diff --git a/android/app/src/main/java/com/example/petstoremobile/viewmodels/ProductListViewModel.java b/android/app/src/main/java/com/example/petstoremobile/viewmodels/ProductListViewModel.java index b22dee6c..e242768f 100644 --- a/android/app/src/main/java/com/example/petstoremobile/viewmodels/ProductListViewModel.java +++ b/android/app/src/main/java/com/example/petstoremobile/viewmodels/ProductListViewModel.java @@ -38,11 +38,29 @@ public class ProductListViewModel extends ViewModel { this.categoryRepository = categoryRepository; } + /** + * Returns the LiveData for the list of products. + */ public LiveData> getProducts() { return products; } + + /** + * Returns the LiveData for the list of categories for filtering. + */ public LiveData> getCategories() { return categories; } + + /** + * Returns the LiveData for the loading state. + */ public LiveData getIsLoading() { return isLoading; } + + /** + * Checks if the last page of products has been reached. + */ public boolean isLastPage() { return isLastPage; } + /** + * Loads products from the repository with the specified filters. + */ public void loadProducts(boolean reset, String query, Long categoryId) { if (isLoading.getValue() != null && isLoading.getValue() && !reset) return; @@ -70,6 +88,9 @@ public class ProductListViewModel extends ViewModel { }); } + /** + * Loads the list of categories for filtering options. + */ public void loadCategories() { observeOnce(productRepository.getCategoryDropdowns(), resource -> { if (resource != null && resource.status == Resource.Status.SUCCESS && resource.data != null) { diff --git a/android/app/src/main/java/com/example/petstoremobile/viewmodels/ProductSupplierDetailViewModel.java b/android/app/src/main/java/com/example/petstoremobile/viewmodels/ProductSupplierDetailViewModel.java index 2cbf5036..66d0201e 100644 --- a/android/app/src/main/java/com/example/petstoremobile/viewmodels/ProductSupplierDetailViewModel.java +++ b/android/app/src/main/java/com/example/petstoremobile/viewmodels/ProductSupplierDetailViewModel.java @@ -40,28 +40,54 @@ public class ProductSupplierDetailViewModel extends ViewModel { this.supplierRepository = supplierRepository; } + /** + * Sets the composite key for the product-supplier relationship and enables editing mode. + */ public void setEditMode(long productId, long supplierId) { this.isEditing = true; this.editProductId = productId; this.editSupplierId = supplierId; } + /** + * Loads the product-supplier details from the repository. + */ public LiveData> loadProductSupplier() { return psRepository.getProductSupplierById(editProductId, editSupplierId); } + /** + * Checks if the fragment is in editing mode. + */ public boolean isEditing() { return isEditing; } + + /** + * Returns the product ID for the relationship being edited. + */ public long getEditProductId() { return editProductId; } + + /** + * Returns the supplier ID for the relationship being edited. + */ public long getEditSupplierId() { return editSupplierId; } + /** + * Loads products for the dropdown selection. + */ public LiveData>> loadProducts() { return productRepository.getAllProducts(null, null, 0, 200, "prodName"); } + /** + * Loads suppliers for the dropdown selection. + */ public LiveData>> loadSuppliers() { return supplierRepository.getAllSuppliers(0, 200, null, "supCompany"); } + /** + * Saves or updates the product-supplier relationship. + */ public LiveData> saveProductSupplier(ProductSupplierDTO dto) { if (isEditing) { return psRepository.updateProductSupplier(editProductId, editSupplierId, dto); @@ -70,13 +96,30 @@ public class ProductSupplierDetailViewModel extends ViewModel { } } + /** + * Deletes the current product-supplier relationship. + */ public LiveData> deleteProductSupplier() { return psRepository.deleteProductSupplier(editProductId, editSupplierId); } + /** + * Updates the product list. + */ public void setProductList(List list) { productList.setValue(list); } + + /** + * Returns the LiveData for the product list. + */ public LiveData> getProductList() { return productList; } + /** + * Updates the supplier list. + */ public void setSupplierList(List list) { supplierList.setValue(list); } + + /** + * Returns the LiveData for the supplier list. + */ public LiveData> getSupplierList() { return supplierList; } } diff --git a/android/app/src/main/java/com/example/petstoremobile/viewmodels/ProductSupplierListViewModel.java b/android/app/src/main/java/com/example/petstoremobile/viewmodels/ProductSupplierListViewModel.java index 930770a4..0a568e51 100644 --- a/android/app/src/main/java/com/example/petstoremobile/viewmodels/ProductSupplierListViewModel.java +++ b/android/app/src/main/java/com/example/petstoremobile/viewmodels/ProductSupplierListViewModel.java @@ -44,12 +44,34 @@ public class ProductSupplierListViewModel extends ViewModel { this.supplierRepository = supplierRepository; } + /** + * Returns the LiveData for the product-supplier relationship list. + */ public LiveData> getProductSuppliers() { return productSuppliers; } + + /** + * Returns the LiveData for the list of products for filtering. + */ public LiveData> getProducts() { return products; } + + /** + * Returns the LiveData for the list of suppliers for filtering. + */ public LiveData> getSuppliers() { return suppliers; } + + /** + * Returns the LiveData for the loading state. + */ public LiveData getIsLoading() { return isLoading; } + + /** + * Checks if the last page of product-supplier relationships has been reached. + */ public boolean isLastPage() { return isLastPage; } + /** + * Loads product-supplier relationships from the repository with the specified filters. + */ public void loadProductSuppliers(boolean reset, String query, Long productId, Long supplierId) { if (isLoading.getValue() != null && isLoading.getValue() && !reset) return; @@ -77,6 +99,9 @@ public class ProductSupplierListViewModel extends ViewModel { }); } + /** + * Loads products and suppliers for filtering options. + */ public void loadFilterData() { observeOnce(productRepository.getAllProducts(null, null, 0, 100, "prodName"), resource -> { if (resource != null && resource.status == Resource.Status.SUCCESS && resource.data != null) { @@ -103,6 +128,9 @@ public class ProductSupplierListViewModel extends ViewModel { }); } + /** + * Deletes multiple product-supplier relationships by their composite keys. + */ public LiveData> bulkDeleteProductSuppliers(List ids) { return psRepository.bulkDeleteProductSuppliers(new BulkDeleteRequest(ids)); } diff --git a/android/app/src/main/java/com/example/petstoremobile/viewmodels/PurchaseOrderDetailViewModel.java b/android/app/src/main/java/com/example/petstoremobile/viewmodels/PurchaseOrderDetailViewModel.java index 436cfa4c..c68e1d89 100644 --- a/android/app/src/main/java/com/example/petstoremobile/viewmodels/PurchaseOrderDetailViewModel.java +++ b/android/app/src/main/java/com/example/petstoremobile/viewmodels/PurchaseOrderDetailViewModel.java @@ -20,6 +20,9 @@ public class PurchaseOrderDetailViewModel extends ViewModel { this.repository = repository; } + /** + * Loads the purchase order details from the repository. + */ public LiveData> loadPurchaseOrder(long id) { return repository.getPurchaseOrderById(id); } diff --git a/android/app/src/main/java/com/example/petstoremobile/viewmodels/PurchaseOrderListViewModel.java b/android/app/src/main/java/com/example/petstoremobile/viewmodels/PurchaseOrderListViewModel.java index 923d336e..3febfe0e 100644 --- a/android/app/src/main/java/com/example/petstoremobile/viewmodels/PurchaseOrderListViewModel.java +++ b/android/app/src/main/java/com/example/petstoremobile/viewmodels/PurchaseOrderListViewModel.java @@ -38,11 +38,29 @@ public class PurchaseOrderListViewModel extends ViewModel { this.storeRepository = storeRepository; } + /** + * Returns the LiveData for the list of purchase orders. + */ public LiveData> getPurchaseOrders() { return purchaseOrders; } + + /** + * Returns the LiveData for the list of stores for filtering. + */ public LiveData> getStores() { return stores; } + + /** + * Returns the LiveData for the loading state. + */ public LiveData getIsLoading() { return isLoading; } + + /** + * Checks if the last page of purchase orders has been reached. + */ public boolean isLastPage() { return isLastPage; } + /** + * Loads purchase orders from the repository with the specified filters. + */ public void loadPurchaseOrders(boolean reset, String query, Long storeId) { if (isLoading.getValue() != null && isLoading.getValue() && !reset) return; @@ -70,6 +88,9 @@ public class PurchaseOrderListViewModel extends ViewModel { }); } + /** + * Loads the list of stores for filtering options. + */ public void loadStores() { observeOnce(storeRepository.getAllStores(0, 100), resource -> { if (resource != null && resource.status == Resource.Status.SUCCESS && resource.data != null) { diff --git a/android/app/src/main/java/com/example/petstoremobile/viewmodels/RefundViewModel.java b/android/app/src/main/java/com/example/petstoremobile/viewmodels/RefundViewModel.java index ff3d069e..bf96e89b 100644 --- a/android/app/src/main/java/com/example/petstoremobile/viewmodels/RefundViewModel.java +++ b/android/app/src/main/java/com/example/petstoremobile/viewmodels/RefundViewModel.java @@ -20,6 +20,9 @@ import javax.inject.Inject; import dagger.hilt.android.lifecycle.HiltViewModel; +/** + * ViewModel for processing and managing refund requests. + */ @HiltViewModel public class RefundViewModel extends ViewModel { private final SaleRepository saleRepository; @@ -34,35 +37,59 @@ public class RefundViewModel extends ViewModel { this.saleRepository = saleRepository; } + /** + * Loads all sales from the repository for refund selection. + */ public LiveData>> loadAllSales() { return saleRepository.getAllSales(0, 1000, null, null, null, null, null, "saleDate,desc"); } + /** + * Sets the list of all available sales. + */ public void setAllSales(List sales) { allSales.setValue(sales); } + /** + * Returns the list of all available sales. + */ public List getAllSalesList() { return allSales.getValue(); } + /** + * Sets the current sale being processed for a refund and computes refundable items. + */ public void setCurrentSale(SaleDTO sale) { currentSale.setValue(sale); buildRefundableItems(); } + /** + * Returns the current sale being processed. + */ public SaleDTO getCurrentSale() { return currentSale.getValue(); } + /** + * Returns the LiveData for the list of items available for refund in the current sale. + */ public LiveData> getAvailableItems() { return availableItems; } + /** + * Returns the LiveData for the items added to the refund cart. + */ public LiveData> getRefundCart() { return refundCart; } + /** + * Builds the list of items available for refund, accounting for previous refunds. + */ private void buildRefundableItems() { SaleDTO sale = currentSale.getValue(); List sales = allSales.getValue(); @@ -103,6 +130,9 @@ public class RefundViewModel extends ViewModel { refundCart.setValue(new ArrayList<>()); } + /** + * Adds an item to the refund cart. + */ public void addToCart(RefundItem item, int qty) { List cart = new ArrayList<>(refundCart.getValue()); boolean merged = false; @@ -120,12 +150,18 @@ public class RefundViewModel extends ViewModel { refundCart.setValue(cart); } + /** + * Removes an item from the refund cart. + */ public void removeFromCart(RefundItem item) { List cart = new ArrayList<>(refundCart.getValue()); cart.remove(item); refundCart.setValue(cart); } + /** + * Calculates the total refund amount, proportional to the original total. + */ public BigDecimal calculateRefundTotal() { SaleDTO sale = currentSale.getValue(); List cart = refundCart.getValue(); @@ -153,6 +189,9 @@ public class RefundViewModel extends ViewModel { return originalTotal.abs().multiply(ratio).setScale(2, RoundingMode.HALF_UP); } + /** + * Submits the refund transaction to the repository. + */ public LiveData> submitRefund(String paymentMethod) { SaleDTO sale = currentSale.getValue(); List cart = refundCart.getValue(); diff --git a/android/app/src/main/java/com/example/petstoremobile/viewmodels/SaleDetailViewModel.java b/android/app/src/main/java/com/example/petstoremobile/viewmodels/SaleDetailViewModel.java index 68369cce..4160659e 100644 --- a/android/app/src/main/java/com/example/petstoremobile/viewmodels/SaleDetailViewModel.java +++ b/android/app/src/main/java/com/example/petstoremobile/viewmodels/SaleDetailViewModel.java @@ -24,6 +24,9 @@ import javax.inject.Inject; import dagger.hilt.android.lifecycle.HiltViewModel; +/** + * ViewModel for managing sale details, including creating new sales and viewing existing ones. + */ @HiltViewModel public class SaleDetailViewModel extends ViewModel { private final SaleRepository saleRepository; @@ -55,77 +58,150 @@ public class SaleDetailViewModel extends ViewModel { this.couponRepository = couponRepository; } + /** + * Sets the sale ID and whether the view is read-only. + */ public void setSaleId(long id, boolean viewOnly) { this.saleId = id; this.viewOnly = viewOnly; } + /** + * Returns the current sale ID. + */ public long getSaleId() { return saleId; } + + /** + * Returns true if the view is in read-only mode. + */ public boolean isViewOnly() { return viewOnly; } + /** + * Loads the details of a specific sale by its ID. + */ public LiveData> loadSaleDetails() { return saleRepository.getSaleById(saleId); } + /** + * Loads the list of stores for selection. + */ public LiveData>> loadStores() { return storeRepository.getStoreDropdowns(); } + /** + * Loads the list of customers for selection. + */ public LiveData>> loadCustomers() { return customerRepository.getCustomerDropdowns(); } + /** + * Loads the list of products for sale selection. + */ public LiveData>> loadProducts() { return productRepository.getAllProducts(null, null, 0, 200, null); } + /** + * Submits a new sale to the repository. + */ public LiveData> createSale(SaleDTO sale) { return saleRepository.createSale(sale); } + /** + * Sets the local list of stores. + */ public void setStoreList(List list) { storeList.setValue(list); } + + /** + * Returns the LiveData for the local list of stores. + */ public LiveData> getStoreList() { return storeList; } + /** + * Sets the local list of customers. + */ public void setCustomerList(List list) { customerList.setValue(list); } + + /** + * Returns the LiveData for the local list of customers. + */ public LiveData> getCustomerList() { return customerList; } + /** + * Sets the local list of products. + */ public void setProductList(List list) { productList.setValue(list); } + + /** + * Returns the LiveData for the local list of products. + */ public LiveData> getProductList() { return productList; } + /** + * Adds an item to the sale cart. + */ public void addToCart(SaleDTO.SaleItemDTO item) { List currentCart = new ArrayList<>(cartItems.getValue()); currentCart.add(item); cartItems.setValue(currentCart); } + /** + * Removes an item from the sale cart by product ID. + */ public void removeFromCart(Long prodId) { List currentCart = new ArrayList<>(cartItems.getValue()); currentCart.removeIf(item -> item.getProdId().equals(prodId)); cartItems.setValue(currentCart); } + /** + * Returns the LiveData for the list of items in the cart. + */ public LiveData> getCartItems() { return cartItems; } + /** + * Looks up a coupon by its code. + */ public LiveData> lookupCoupon(String code) { return couponRepository.getCouponByCode(code); } + /** + * Sets the currently applied coupon. + */ public void setAppliedCoupon(CouponDTO coupon) { appliedCoupon.setValue(coupon); } + /** + * Sets whether to use loyalty points for the current sale. + */ public void setUseLoyaltyPoints(boolean use) { useLoyaltyPoints.setValue(use); } + /** + * Returns the LiveData for whether loyalty points are being used. + */ public LiveData getUseLoyaltyPoints() { return useLoyaltyPoints; } + /** + * Returns the LiveData for the selected customer's full data. + */ public LiveData getSelectedCustomerData() { return selectedCustomerData; } + /** + * Selects a customer and loads their full data. + */ public void selectCustomer(Long customerId) { if (customerId == null) { selectedCustomerData.setValue(null); @@ -142,23 +218,38 @@ public class SaleDetailViewModel extends ViewModel { }); } + /** + * Clears the currently applied coupon. + */ public void clearCoupon() { appliedCoupon.setValue(null); } + /** + * Returns the LiveData for the applied coupon. + */ public LiveData getAppliedCoupon() { return appliedCoupon; } + /** + * Returns the ID of the applied coupon. + */ public Long getAppliedCouponId() { CouponDTO coupon = appliedCoupon.getValue(); return coupon != null ? coupon.getCouponId() : null; } + /** + * Calculates the total discount (coupon + loyalty). + */ public BigDecimal calculateDiscount() { return calculateCouponDiscount().add(calculateLoyaltyDiscount()); } + /** + * Calculates the discount from the applied coupon. + */ public BigDecimal calculateCouponDiscount() { CouponDTO coupon = appliedCoupon.getValue(); if (coupon == null || coupon.getDiscountValue() == null) return BigDecimal.ZERO; @@ -170,6 +261,9 @@ public class SaleDetailViewModel extends ViewModel { } } + /** + * Calculates the discount from using loyalty points. + */ public BigDecimal calculateLoyaltyDiscount() { if (Boolean.FALSE.equals(useLoyaltyPoints.getValue())) return BigDecimal.ZERO; CustomerDTO customer = selectedCustomerData.getValue(); @@ -184,11 +278,17 @@ public class SaleDetailViewModel extends ViewModel { return BigDecimal.valueOf(pointsToUse).multiply(BigDecimal.valueOf(0.05)).setScale(2, java.math.RoundingMode.HALF_UP); } + /** + * Calculates the number of loyalty points to be used. + */ public int calculatePointsToUse() { BigDecimal loyaltyDiscount = calculateLoyaltyDiscount(); return loyaltyDiscount.divide(BigDecimal.valueOf(0.05), 0, java.math.RoundingMode.HALF_UP).intValue(); } + /** + * Calculates the subtotal of all items in the cart. + */ public BigDecimal calculateSubtotal() { BigDecimal total = BigDecimal.ZERO; List items = cartItems.getValue(); @@ -206,10 +306,16 @@ public class SaleDetailViewModel extends ViewModel { return total; } + /** + * Returns the LiveData for the loading state. + */ public LiveData getIsLoading() { return isLoading; } + /** + * Sets the loading state. + */ public void setLoading(boolean loading) { isLoading.setValue(loading); } diff --git a/android/app/src/main/java/com/example/petstoremobile/viewmodels/SaleListViewModel.java b/android/app/src/main/java/com/example/petstoremobile/viewmodels/SaleListViewModel.java index aee0f948..e3f4f7ee 100644 --- a/android/app/src/main/java/com/example/petstoremobile/viewmodels/SaleListViewModel.java +++ b/android/app/src/main/java/com/example/petstoremobile/viewmodels/SaleListViewModel.java @@ -22,6 +22,9 @@ import javax.inject.Inject; import dagger.hilt.android.lifecycle.HiltViewModel; +/** + * ViewModel for managing the list of sales transactions and applying filters. + */ @HiltViewModel public class SaleListViewModel extends ViewModel { private final SaleRepository saleRepository; @@ -44,12 +47,34 @@ public class SaleListViewModel extends ViewModel { this.customerRepository = customerRepository; } + /** + * Returns the LiveData for the list of sales. + */ public LiveData> getSales() { return sales; } + + /** + * Returns the LiveData for the list of available stores. + */ public LiveData> getStores() { return stores; } + + /** + * Returns the LiveData for the list of available customers. + */ public LiveData> getCustomers() { return customers; } + + /** + * Returns the LiveData for the loading state. + */ public LiveData getIsLoading() { return isLoading; } + + /** + * Returns true if the current page is the last page of results. + */ public boolean isLastPage() { return isLastPage; } + /** + * Loads a page of sales based on search and filter criteria. + */ public void loadSales(boolean reset, String query, String paymentMethod, Long storeId, Boolean isRefund, Long customerId) { if (isLoading.getValue() != null && isLoading.getValue() && !reset) return; @@ -75,6 +100,9 @@ public class SaleListViewModel extends ViewModel { }); } + /** + * Loads available stores for filtering. + */ public void loadStores() { observeOnce(storeRepository.getAllStores(0, 100), resource -> { if (resource != null && resource.status == Resource.Status.SUCCESS && resource.data != null) { @@ -83,6 +111,9 @@ public class SaleListViewModel extends ViewModel { }); } + /** + * Loads available customers for filtering. + */ public void loadCustomers() { observeOnce(customerRepository.getAllCustomers(0, 500), resource -> { if (resource != null && resource.status == Resource.Status.SUCCESS && resource.data != null) { @@ -91,6 +122,9 @@ public class SaleListViewModel extends ViewModel { }); } + /** + * Observes a LiveData once, removing the observer after the first non-loading response. + */ private void observeOnce(LiveData> liveData, Observer> handler) { liveData.observeForever(new Observer>() { @Override diff --git a/android/app/src/main/java/com/example/petstoremobile/viewmodels/ServiceDetailViewModel.java b/android/app/src/main/java/com/example/petstoremobile/viewmodels/ServiceDetailViewModel.java index 625abb92..352a08b7 100644 --- a/android/app/src/main/java/com/example/petstoremobile/viewmodels/ServiceDetailViewModel.java +++ b/android/app/src/main/java/com/example/petstoremobile/viewmodels/ServiceDetailViewModel.java @@ -26,24 +26,39 @@ public class ServiceDetailViewModel extends ViewModel { this.repository = repository; } + /** + * Sets the service ID and initializes the editing mode. + */ public void setServiceId(long id) { this.serviceId = id; initMode(id != -1); } + /** + * Returns the current service ID. + */ public long getServiceId() { return serviceId; } + /** + * Checks if the fragment is in editing mode. + */ public boolean isEditing() { ViewState current = viewState.getValue(); return current != null && current.isEditing; } + /** + * Returns the LiveData for the view state. + */ public LiveData getViewState() { return viewState; } + /** + * Initializes the UI mode (Create vs Edit). + */ public void initMode(boolean isEditing) { updateViewState(state -> { state.isEditing = isEditing; @@ -55,6 +70,9 @@ public class ServiceDetailViewModel extends ViewModel { }); } + /** + * Fetches service details from the repository. + */ public LiveData> loadService() { MutableLiveData> result = new MutableLiveData<>(); observeOnce(repository.getServiceById(serviceId), resource -> { @@ -72,6 +90,9 @@ public class ServiceDetailViewModel extends ViewModel { return result; } + /** + * Saves or updates the service record. + */ public LiveData> saveService(ServiceDTO dto) { updateViewState(state -> { state.serviceName = safeText(dto.getServiceName()); @@ -88,6 +109,9 @@ public class ServiceDetailViewModel extends ViewModel { return repository.createService(dto); } + /** + * Deletes the current service record. + */ public LiveData> deleteService() { return repository.deleteService(serviceId); } diff --git a/android/app/src/main/java/com/example/petstoremobile/viewmodels/ServiceListViewModel.java b/android/app/src/main/java/com/example/petstoremobile/viewmodels/ServiceListViewModel.java index bbdbe270..7e3e9092 100644 --- a/android/app/src/main/java/com/example/petstoremobile/viewmodels/ServiceListViewModel.java +++ b/android/app/src/main/java/com/example/petstoremobile/viewmodels/ServiceListViewModel.java @@ -35,10 +35,24 @@ public class ServiceListViewModel extends ViewModel { this.repository = repository; } + /** + * Returns the LiveData for the list of services. + */ public LiveData> getServices() { return services; } + + /** + * Returns the LiveData for the loading state. + */ public LiveData getIsLoading() { return isLoading; } + + /** + * Checks if the last page of services has been reached. + */ public boolean isLastPage() { return isLastPage; } + /** + * Loads services from the repository with the specified filters. + */ public void loadServices(boolean reset, String query) { if (isLoading.getValue() != null && isLoading.getValue() && !reset) return; @@ -76,6 +90,9 @@ public class ServiceListViewModel extends ViewModel { }); } + /** + * Deletes multiple services by their IDs. + */ public LiveData> bulkDeleteServices(List ids) { return repository.bulkDeleteServices(new BulkDeleteRequest(ids)); } diff --git a/android/app/src/main/java/com/example/petstoremobile/viewmodels/StaffDetailViewModel.java b/android/app/src/main/java/com/example/petstoremobile/viewmodels/StaffDetailViewModel.java index 7927465e..8dd538a9 100644 --- a/android/app/src/main/java/com/example/petstoremobile/viewmodels/StaffDetailViewModel.java +++ b/android/app/src/main/java/com/example/petstoremobile/viewmodels/StaffDetailViewModel.java @@ -31,31 +31,52 @@ public class StaffDetailViewModel extends ViewModel { this.storeRepository = storeRepository; } + /** + * Loads store dropdown options. + */ public LiveData>> loadStores() { return storeRepository.getStoreDropdowns(); } + /** + * Returns the LiveData for the store list. + */ public LiveData> getStoreList() { return storeList; } + /** + * Updates the store list. + */ public void setStoreList(List list) { storeList.setValue(list); } + /** + * Loads the employee details from the repository. + */ public LiveData> loadEmployee(long id) { return repository.getEmployeeById(id); } + /** + * Sets the current employee ID and editing mode. + */ public void setEmployeeId(long id, boolean isEditing) { this.employeeId = id; this.isEditing = isEditing; } + /** + * Returns the current employee ID. + */ public long getEmployeeId() { return employeeId; } + /** + * Checks if the fragment is in editing mode. + */ public boolean isEditing() { return isEditing; } @@ -68,6 +89,9 @@ public class StaffDetailViewModel extends ViewModel { return dto; } + /** + * Saves or updates the employee record. + */ public LiveData> saveEmployee(EmployeeDTO dto) { if (isEditing && employeeId > 0) { return repository.updateEmployee(employeeId, dto); @@ -76,6 +100,9 @@ public class StaffDetailViewModel extends ViewModel { } } + /** + * Deletes the current employee record. + */ public LiveData> deleteEmployee() { return repository.deleteEmployee(employeeId); } diff --git a/android/app/src/main/java/com/example/petstoremobile/viewmodels/StaffListViewModel.java b/android/app/src/main/java/com/example/petstoremobile/viewmodels/StaffListViewModel.java index 3dc40816..ed22e3e5 100644 --- a/android/app/src/main/java/com/example/petstoremobile/viewmodels/StaffListViewModel.java +++ b/android/app/src/main/java/com/example/petstoremobile/viewmodels/StaffListViewModel.java @@ -19,6 +19,9 @@ import javax.inject.Inject; import dagger.hilt.android.lifecycle.HiltViewModel; +/** + * ViewModel for managing the list of employees, including filtering and pagination. + */ @HiltViewModel public class StaffListViewModel extends ViewModel { private final EmployeeRepository repository; @@ -43,11 +46,29 @@ public class StaffListViewModel extends ViewModel { this.storeRepository = storeRepository; } + /** + * Returns the LiveData for the list of filtered employees. + */ public LiveData> getFilteredEmployees() { return filteredEmployees; } + + /** + * Returns the LiveData for the list of stores for filtering. + */ public LiveData> getStores() { return stores; } + + /** + * Returns the LiveData for the loading state. + */ public LiveData getIsLoading() { return isLoading; } + + /** + * Checks if the last page of employees has been reached. + */ public boolean isLastPage() { return isLastPage; } + /** + * Loads the full list of staff from the repository. + */ public void loadStaff(boolean reset) { if (isLoading.getValue() != null && isLoading.getValue() && !reset) return; @@ -76,6 +97,9 @@ public class StaffListViewModel extends ViewModel { }); } + /** + * Loads the list of stores for filtering options. + */ public void loadStores() { observeOnce(storeRepository.getAllStores(0, 100), resource -> { if (resource != null && resource.status == Resource.Status.SUCCESS && resource.data != null) { @@ -84,6 +108,9 @@ public class StaffListViewModel extends ViewModel { }); } + /** + * Observes a LiveData once + */ private void observeOnce(LiveData> liveData, Observer> handler) { liveData.observeForever(new Observer>() { @Override @@ -96,6 +123,9 @@ public class StaffListViewModel extends ViewModel { }); } + /** + * Filters the employee list locally based on query, store, and status. + */ public void filter(String query, Long storeId, String status) { this.lastQuery = query; this.lastStoreId = storeId; @@ -103,6 +133,9 @@ public class StaffListViewModel extends ViewModel { applyFilter(employees.getValue()); } + /** + * Applies the filters to the full list and updates the filtered LiveData. + */ private void applyFilter(List all) { if (all == null) return; diff --git a/android/app/src/main/java/com/example/petstoremobile/viewmodels/SupplierDetailViewModel.java b/android/app/src/main/java/com/example/petstoremobile/viewmodels/SupplierDetailViewModel.java index 54f83ef9..63e03b7d 100644 --- a/android/app/src/main/java/com/example/petstoremobile/viewmodels/SupplierDetailViewModel.java +++ b/android/app/src/main/java/com/example/petstoremobile/viewmodels/SupplierDetailViewModel.java @@ -26,24 +26,39 @@ public class SupplierDetailViewModel extends ViewModel { this.repository = repository; } + /** + * Sets the supplier ID and initializes the editing mode. + */ public void setSupId(long id) { this.supId = id; initMode(id != -1); } + /** + * Returns the current supplier ID. + */ public long getSupId() { return supId; } + /** + * Checks if the fragment is in editing mode. + */ public boolean isEditing() { ViewState current = viewState.getValue(); return current != null && current.isEditing; } + /** + * Returns the LiveData for the view state. + */ public LiveData getViewState() { return viewState; } + /** + * Initializes the UI mode (Create vs Edit). + */ public void initMode(boolean isEditing) { updateViewState(state -> { state.isEditing = isEditing; @@ -55,6 +70,9 @@ public class SupplierDetailViewModel extends ViewModel { }); } + /** + * Fetches supplier details from the repository. + */ public LiveData> loadSupplier() { MutableLiveData> result = new MutableLiveData<>(); observeOnce(repository.getSupplierById(supId), resource -> { @@ -73,6 +91,9 @@ public class SupplierDetailViewModel extends ViewModel { return result; } + /** + * Saves or updates the supplier record. + */ public LiveData> saveSupplier(SupplierDTO dto) { if (isEditing()) { dto.setSupId(supId); @@ -81,6 +102,9 @@ public class SupplierDetailViewModel extends ViewModel { return repository.createSupplier(dto); } + /** + * Deletes the current supplier record. + */ public LiveData> deleteSupplier() { return repository.deleteSupplier(supId); } diff --git a/android/app/src/main/java/com/example/petstoremobile/viewmodels/SupplierListViewModel.java b/android/app/src/main/java/com/example/petstoremobile/viewmodels/SupplierListViewModel.java index 33373e90..700977cf 100644 --- a/android/app/src/main/java/com/example/petstoremobile/viewmodels/SupplierListViewModel.java +++ b/android/app/src/main/java/com/example/petstoremobile/viewmodels/SupplierListViewModel.java @@ -34,10 +34,24 @@ public class SupplierListViewModel extends ViewModel { this.repository = repository; } + /** + * Returns the LiveData for the list of suppliers. + */ public LiveData> getSuppliers() { return suppliers; } + + /** + * Returns the LiveData for the loading state. + */ public LiveData getIsLoading() { return isLoading; } + + /** + * Checks if the last page of suppliers has been reached. + */ public boolean isLastPage() { return isLastPage; } + /** + * Loads suppliers from the repository with the specified filters. + */ public void loadSuppliers(boolean reset, String query) { if (isLoading.getValue() != null && isLoading.getValue() && !reset) return; @@ -77,6 +91,9 @@ public class SupplierListViewModel extends ViewModel { }); } + /** + * Deletes multiple suppliers by their IDs. + */ public LiveData> bulkDeleteSuppliers(List ids) { return repository.bulkDeleteSuppliers(new BulkDeleteRequest(ids)); } diff --git a/android/app/src/main/java/com/example/petstoremobile/websocket/StompChatManager.java b/android/app/src/main/java/com/example/petstoremobile/websocket/StompChatManager.java index 3aad4b8d..8d77daef 100644 --- a/android/app/src/main/java/com/example/petstoremobile/websocket/StompChatManager.java +++ b/android/app/src/main/java/com/example/petstoremobile/websocket/StompChatManager.java @@ -18,25 +18,50 @@ import ua.naiksoftware.stomp.Stomp; import ua.naiksoftware.stomp.StompClient; import ua.naiksoftware.stomp.dto.StompHeader; -//Used to handle the websocket connection for the chat +/** + * Manages WebSocket connections and STOMP protocol messaging for the chat system. + */ public class StompChatManager { private static final String TAG = "StompChatManager"; - //Interface for when a message is received + /** + * Interface for receiving new chat messages. + */ public interface MessageListener { + /** + * Called when a new message is received for the current conversation. + */ void onMessageReceived(MessageDTO message); } - //Interface for when a conversation is created or updated + /** + * Interface for receiving updates to the list of conversations. + */ public interface ConversationListener { + /** + * Called when a conversation is created or its details are updated. + */ void onConversationUpdated(ConversationDTO conversation); } - //Interface for when the websocket connection is opened, closed, or has an error + /** + * Interface for monitoring the status of the WebSocket connection. + */ public interface ConnectionListener { + /** + * Called when the connection is successfully established. + */ void onSocketOpened(); + + /** + * Called when the connection is closed. + */ void onSocketClosed(); + + /** + * Called when a connection error occurs. + */ void onSocketError(); } @@ -59,16 +84,25 @@ public class StompChatManager { private boolean manualDisconnect; private Long pendingConversationId; + /** + * Initializes the manager with authentication and server details. + */ public StompChatManager(String authToken, String role, String baseUrl) { this.authToken = authToken; this.role = role == null ? "" : role.trim().toUpperCase(Locale.ROOT); this.baseUrl = baseUrl; } + /** + * Sets the listener for incoming messages. + */ public void setMessageListener(MessageListener listener) { this.messageListener = listener; } + /** + * Sets the listener for conversation list updates. + */ public void setConversationListener(ConversationListener listener) { this.conversationListener = listener; } @@ -77,7 +111,10 @@ public class StompChatManager { this.connectionListener = listener; } - // Set up a stomp connection + /** + * Establishes a connection to the WebSocket server using STOMP. + * Reconnects automatically unless manually disconnected. + */ public void connect() { if (authToken == null || authToken.isBlank()) { Log.e(TAG, "Cannot connect websocket without token"); @@ -143,7 +180,10 @@ public class StompChatManager { )); } - // Subscribes to updates for a specific conversation + /** + * Subscribes to updates for a specific conversation. + * If not connected, the subscription is queued until the connection is established. + */ public void subscribeToConversation(Long conversationId) { pendingConversationId = conversationId; if (!isConnected || stompClient == null) { @@ -154,7 +194,9 @@ public class StompChatManager { subscribeToTopic(conversationId); } - // Clears the current conversation subscription + /** + * Stops listening for messages in the current conversation. + */ public void clearConversationSubscription() { pendingConversationId = null; if (topicDisposable != null && !topicDisposable.isDisposed()) { @@ -163,7 +205,9 @@ public class StompChatManager { } } - //helper function to subscribe to a specific conversation topic + /** + * Subscribes to the specific STOMP topic for a conversation's messages. + */ private void subscribeToTopic(Long conversationId) { if (topicDisposable != null && !topicDisposable.isDisposed()) { topicDisposable.dispose(); @@ -189,7 +233,9 @@ public class StompChatManager { compositeDisposable.add(topicDisposable); } - // Listens for conversation updates and refresh the chat list + /** + * Listens for conversation updates and refresh the chat list + */ private void subscribeToConversationFeeds() { if (conversationsDisposable != null && !conversationsDisposable.isDisposed()) { conversationsDisposable.dispose(); @@ -254,7 +300,9 @@ public class StompChatManager { compositeDisposable.add(errorQueueDisposable); } - // Disconnects the stomp connection + /** + * Disconnects the stomp connection + */ public void disconnect() { manualDisconnect = true; isConnected = false; @@ -267,7 +315,9 @@ public class StompChatManager { } } - // Make the URL for the websocket connection + /** + * Make the URL for the websocket connection + */ private String buildWebSocketUrl() { String cleanBaseUrl = baseUrl.endsWith("/") ? baseUrl.substring(0, baseUrl.length() - 1) @@ -281,12 +331,16 @@ public class StompChatManager { return cleanBaseUrl + "/ws/chat"; } - // Helper to check if the current user is a customer + /** + * Helper to check if the current user is a customer + */ private boolean isCustomer() { return "CUSTOMER".equals(role); } - // if connection drops, try to reconnect after 1 second + /** + * if connection drops, try to reconnect after 1 second + */ private void scheduleReconnect() { if (manualDisconnect) { return;