From 811edf842b3ad14fcabe615326b42a829ad5f617 Mon Sep 17 00:00:00 2001 From: Alex <78383757+Lextical@users.noreply.github.com> Date: Wed, 8 Apr 2026 02:22:34 -0600 Subject: [PATCH] converted new fragments to use hilt, MVVM and jetpack nav --- .../listfragments/AnalyticsFragment.java | 64 +++--- .../listfragments/StaffFragment.java | 50 ++--- .../detailfragments/RefundFragment.java | 77 +++---- .../detailfragments/SaleDetailFragment.java | 192 +++++++++--------- .../detailfragments/StaffDetailFragment.java | 80 ++++---- 5 files changed, 232 insertions(+), 231 deletions(-) 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 04b35623..dbd24c75 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 @@ -7,30 +7,33 @@ import android.view.*; import android.widget.*; import androidx.annotation.NonNull; import androidx.fragment.app.Fragment; -import com.example.petstoremobile.R; -import com.example.petstoremobile.api.RetrofitClient; +import androidx.lifecycle.ViewModelProvider; import com.example.petstoremobile.databinding.FragmentAnalyticsBinding; -import com.example.petstoremobile.dtos.PageResponse; import com.example.petstoremobile.dtos.SaleDTO; -import com.example.petstoremobile.fragments.ListFragment; +import com.example.petstoremobile.utils.UIUtils; +import com.example.petstoremobile.viewmodels.SaleViewModel; +import dagger.hilt.android.AndroidEntryPoint; import java.math.BigDecimal; import java.math.RoundingMode; import java.util.*; -import retrofit2.*; +@AndroidEntryPoint public class AnalyticsFragment extends Fragment { private FragmentAnalyticsBinding binding; + private SaleViewModel saleViewModel; @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { binding = FragmentAnalyticsBinding.inflate(inflater, container, false); + saleViewModel = new ViewModelProvider(this).get(SaleViewModel.class); loadAnalytics(); binding.btnRefreshAnalytics.setOnClickListener(v -> loadAnalytics()); - binding.btnHamburgerAnalytics.setOnClickListener(v -> openDrawer()); + + UIUtils.setupHamburgerMenu(binding.btnHamburgerAnalytics, this); return binding.getRoot(); } @@ -41,16 +44,6 @@ public class AnalyticsFragment extends Fragment { binding = null; } - private void openDrawer() { - Fragment parent = getParentFragment(); - if (parent != null) { - Fragment grandParent = parent.getParentFragment(); - if (grandParent instanceof ListFragment) { - ((ListFragment) grandParent).openDrawer(); - } - } - } - private void loadAnalytics() { // Clear all sections binding.llTopRevenue.removeAllViews(); @@ -65,21 +58,24 @@ public class AnalyticsFragment extends Fragment { binding.tvAvgTransaction.setText("..."); binding.tvTotalItems.setText("..."); - RetrofitClient.getSaleApi(requireContext()).getAllSales(0, 1000, null, null, null, "saleDate,desc") - .enqueue(new Callback>() { - public void onResponse(Call> c, - Response> r) { - if (r.isSuccessful() && r.body() != null) { - computeAndDisplay(r.body().getContent()); - } else { - showError("Failed to load sales data"); + saleViewModel.getAllSales(0, 1000, null, null, null, "saleDate,desc") + .observe(getViewLifecycleOwner(), resource -> { + if (resource != null) { + switch (resource.status) { + case SUCCESS: + if (resource.data != null) { + computeAndDisplay(resource.data.getContent()); + } + break; + case ERROR: + Log.e("Analytics", resource.message != null ? resource.message : "Error loading sales"); + showError("Failed to load sales data"); + break; + case LOADING: + // Already showing loading state in UI + break; } } - - public void onFailure(Call> c, Throwable t) { - Log.e("Analytics", t.getMessage()); - showError("Network error"); - } }); } @@ -250,13 +246,12 @@ public class AnalyticsFragment extends Fragment { } } - // Adds a horizontal bar row with label, value and a proportional bar private void addBarRow(LinearLayout parent, String label, String value, float ratio, String color) { + if (getContext() == null) return; LinearLayout row = new LinearLayout(getContext()); row.setOrientation(LinearLayout.VERTICAL); row.setPadding(0, 6, 0, 6); - // Label + value row LinearLayout labelRow = new LinearLayout(getContext()); labelRow.setOrientation(LinearLayout.HORIZONTAL); @@ -276,7 +271,6 @@ public class AnalyticsFragment extends Fragment { labelRow.addView(tvLabel); labelRow.addView(tvValue); - // Bar background LinearLayout barBg = new LinearLayout(getContext()); LinearLayout.LayoutParams bgParams = new LinearLayout.LayoutParams( LinearLayout.LayoutParams.MATCH_PARENT, 12); @@ -284,16 +278,13 @@ public class AnalyticsFragment extends Fragment { barBg.setLayoutParams(bgParams); barBg.setBackgroundColor(Color.parseColor("#EEEEEE")); - // Bar fill View barFill = new View(getContext()); - int fillWidth = (int) (ratio * 100); LinearLayout.LayoutParams fillParams = new LinearLayout.LayoutParams( 0, LinearLayout.LayoutParams.MATCH_PARENT, ratio); barFill.setLayoutParams(fillParams); barFill.setBackgroundColor(Color.parseColor(color)); barBg.addView(barFill); - // Empty space View spacer = new View(getContext()); spacer.setLayoutParams(new LinearLayout.LayoutParams( 0, LinearLayout.LayoutParams.MATCH_PARENT, 1f - ratio)); @@ -305,6 +296,7 @@ public class AnalyticsFragment extends Fragment { } private void addEmptyRow(LinearLayout parent, String message) { + if (getContext() == null) return; TextView tv = new TextView(getContext()); tv.setText(message); tv.setTextColor(Color.parseColor("#888780")); @@ -313,7 +305,7 @@ public class AnalyticsFragment extends Fragment { } private void showError(String msg) { - if (getContext() == null) + if (getContext() == null || binding == null) return; binding.tvTotalRevenue.setText("Error"); binding.tvTotalTransactions.setText("—"); 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 fbaf8473..383d702a 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 @@ -5,23 +5,24 @@ import android.util.Log; import android.view.*; import android.widget.*; import androidx.annotation.NonNull; -import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; +import androidx.lifecycle.ViewModelProvider; import androidx.navigation.fragment.NavHostFragment; import androidx.recyclerview.widget.LinearLayoutManager; import com.example.petstoremobile.R; import com.example.petstoremobile.adapters.EmployeeAdapter; -import com.example.petstoremobile.api.RetrofitClient; import com.example.petstoremobile.databinding.FragmentStaffBinding; import com.example.petstoremobile.dtos.EmployeeDTO; -import com.example.petstoremobile.dtos.PageResponse; import com.example.petstoremobile.utils.UIUtils; +import com.example.petstoremobile.viewmodels.EmployeeViewModel; +import dagger.hilt.android.AndroidEntryPoint; import java.util.*; -import retrofit2.*; +@AndroidEntryPoint public class StaffFragment extends Fragment implements EmployeeAdapter.OnEmployeeClickListener { private FragmentStaffBinding binding; + private EmployeeViewModel employeeViewModel; private List employeeList = new ArrayList<>(); private List filteredList = new ArrayList<>(); private EmployeeAdapter adapter; @@ -30,6 +31,7 @@ public class StaffFragment extends Fragment implements EmployeeAdapter.OnEmploye public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { binding = FragmentStaffBinding.inflate(inflater, container, false); + employeeViewModel = new ViewModelProvider(this).get(EmployeeViewModel.class); setupRecyclerView(); setupSearch(); @@ -39,7 +41,6 @@ public class StaffFragment extends Fragment implements EmployeeAdapter.OnEmploye binding.fabAddStaff.setOnClickListener(v -> openDetail(-1)); UIUtils.setupHamburgerMenu(binding.btnHamburgerStaff, this); - UIUtils.setupFilterToggle(binding.btnToggleFilterStaff, binding.layoutFilterStaff, binding.etSearchStaff); return binding.getRoot(); @@ -79,27 +80,30 @@ public class StaffFragment extends Fragment implements EmployeeAdapter.OnEmploye private void loadStaff() { binding.swipeRefreshStaff.setRefreshing(true); - RetrofitClient.getEmployeeApi(requireContext()).getAllEmployees(0, 100) - .enqueue(new Callback>() { - public void onResponse(Call> c, - Response> r) { - if (binding != null) binding.swipeRefreshStaff.setRefreshing(false); - if (r.isSuccessful() && r.body() != null) { + employeeViewModel.getAllEmployees(0, 100).observe(getViewLifecycleOwner(), resource -> { + if (resource != null) { + switch (resource.status) { + case SUCCESS: + binding.swipeRefreshStaff.setRefreshing(false); + if (resource.data != null) { employeeList.clear(); - employeeList.addAll(r.body().getContent()); + employeeList.addAll(resource.data.getContent()); filter(binding != null ? binding.etSearchStaff.getText().toString() : ""); - } else { - if (getContext() != null) { - Toast.makeText(getContext(), "Failed to load staff", - Toast.LENGTH_SHORT).show(); - } } - } - public void onFailure(Call> c, Throwable t) { - if (binding != null) binding.swipeRefreshStaff.setRefreshing(false); - Log.e("StaffFragment", t.getMessage()); - } - }); + break; + case ERROR: + binding.swipeRefreshStaff.setRefreshing(false); + if (getContext() != null) { + Toast.makeText(getContext(), resource.message != null ? resource.message : "Failed to load staff", + Toast.LENGTH_SHORT).show(); + } + break; + case LOADING: + binding.swipeRefreshStaff.setRefreshing(true); + break; + } + } + }); } private void openDetail(int position) { 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 3d1c7d3c..a0abee8c 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 @@ -7,20 +7,22 @@ import android.view.*; import android.widget.*; import androidx.annotation.NonNull; import androidx.fragment.app.Fragment; +import androidx.lifecycle.ViewModelProvider; import androidx.navigation.fragment.NavHostFragment; import com.example.petstoremobile.R; -import com.example.petstoremobile.api.RetrofitClient; import com.example.petstoremobile.databinding.FragmentRefundBinding; import com.example.petstoremobile.dtos.SaleDTO; -import com.example.petstoremobile.dtos.PageResponse; +import com.example.petstoremobile.viewmodels.SaleViewModel; +import dagger.hilt.android.AndroidEntryPoint; import java.math.BigDecimal; import java.math.RoundingMode; import java.util.*; -import retrofit2.*; +@AndroidEntryPoint public class RefundFragment extends Fragment { private FragmentRefundBinding binding; + private SaleViewModel saleViewModel; private SaleDTO currentSale; private List allSales = new ArrayList<>(); @@ -56,6 +58,7 @@ public class RefundFragment extends Fragment { public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { binding = FragmentRefundBinding.inflate(inflater, container, false); + saleViewModel = new ViewModelProvider(this).get(SaleViewModel.class); setupSpinner(); loadAllSales(); @@ -81,22 +84,25 @@ public class RefundFragment extends Fragment { } private void loadAllSales() { - RetrofitClient.getSaleApi(requireContext()).getAllSales(0, 1000, null, null, null, "saleDate,desc") - .enqueue(new Callback>() { - public void onResponse(Call> c, - Response> r) { - if (r.isSuccessful() && r.body() != null) { - allSales = r.body().getContent(); - // Auto-load if saleId was pre-filled - Bundle args = getArguments(); - if (args != null && args.containsKey("saleId")) { - loadSale(); - } + saleViewModel.getAllSales(0, 1000, null, null, null, "saleDate,desc") + .observe(getViewLifecycleOwner(), resource -> { + if (resource != null) { + switch (resource.status) { + case SUCCESS: + if (resource.data != null) { + allSales = resource.data.getContent(); + // Auto-load if saleId was pre-filled + Bundle args = getArguments(); + if (args != null && args.containsKey("saleId")) { + loadSale(); + } + } + break; + case ERROR: + Log.e("Refund", "Failed to load sales: " + resource.message); + break; } } - public void onFailure(Call> c, Throwable t) { - Log.e("Refund", "Failed to load sales: " + t.getMessage()); - } }); } @@ -270,6 +276,7 @@ public class RefundFragment extends Fragment { } private void addTableHeader(LinearLayout parent) { + if (getContext() == null) return; LinearLayout header = new LinearLayout(getContext()); header.setOrientation(LinearLayout.HORIZONTAL); header.setPadding(0, 0, 0, 8); @@ -290,6 +297,7 @@ public class RefundFragment extends Fragment { private LinearLayout buildItemRow(String name, int qty, BigDecimal unitPrice, boolean isAdd, Runnable action) { + if (getContext() == null) return new LinearLayout(getContext()); LinearLayout row = new LinearLayout(getContext()); row.setOrientation(LinearLayout.HORIZONTAL); row.setGravity(android.view.Gravity.CENTER_VERTICAL); @@ -458,30 +466,25 @@ public class RefundFragment extends Fragment { Log.d("REFUND", "Submitting refund for saleId=" + currentSale.getSaleId() + " items=" + items.size()); - RetrofitClient.getSaleApi(requireContext()).createSale(dto) - .enqueue(new Callback() { - public void onResponse(Call c, Response r) { - if (r.isSuccessful() && r.body() != null) { + saleViewModel.createSale(dto).observe(getViewLifecycleOwner(), resource -> { + if (resource != null) { + switch (resource.status) { + case SUCCESS: + if (resource.data != null) { Toast.makeText(getContext(), - "Refund #" + r.body().getSaleId() + " processed successfully!", + "Refund #" + resource.data.getSaleId() + " processed successfully!", Toast.LENGTH_LONG).show(); navigateBack(); - } else { - try { - String err = r.errorBody().string(); - Log.e("REFUND", "Error: " + err); - Toast.makeText(getContext(), "Error: " + err, - Toast.LENGTH_LONG).show(); - } catch (Exception e) { - Log.e("REFUND", "Failed to read error"); - } } - } - public void onFailure(Call c, Throwable t) { - Log.e("REFUND", "Failure: " + t.getMessage()); - Toast.makeText(getContext(), "Network error", Toast.LENGTH_SHORT).show(); - } - }); + break; + case ERROR: + Log.e("REFUND", "Error: " + resource.message); + Toast.makeText(getContext(), "Error: " + resource.message, + Toast.LENGTH_LONG).show(); + break; + } + } + }); } private void navigateBack() { 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 772a74e0..3667ca9c 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 @@ -6,18 +6,24 @@ import android.view.*; import android.widget.*; import androidx.annotation.NonNull; import androidx.fragment.app.Fragment; +import androidx.lifecycle.ViewModelProvider; import androidx.navigation.fragment.NavHostFragment; import com.example.petstoremobile.R; -import com.example.petstoremobile.api.*; import com.example.petstoremobile.databinding.FragmentSaleDetailBinding; import com.example.petstoremobile.dtos.*; +import com.example.petstoremobile.viewmodels.*; +import dagger.hilt.android.AndroidEntryPoint; import java.math.BigDecimal; import java.util.*; -import retrofit2.*; +@AndroidEntryPoint public class SaleDetailFragment extends Fragment { private FragmentSaleDetailBinding binding; + private SaleViewModel saleViewModel; + private StoreViewModel storeViewModel; + private CustomerViewModel customerViewModel; + private ProductViewModel productViewModel; private boolean viewOnly = false; private long saleId = -1; @@ -34,6 +40,11 @@ public class SaleDetailFragment extends Fragment { Bundle savedInstanceState) { binding = FragmentSaleDetailBinding.inflate(inflater, container, false); + saleViewModel = new ViewModelProvider(this).get(SaleViewModel.class); + storeViewModel = new ViewModelProvider(this).get(StoreViewModel.class); + customerViewModel = new ViewModelProvider(this).get(CustomerViewModel.class); + productViewModel = new ViewModelProvider(this).get(ProductViewModel.class); + binding.spinnerPaymentMethod.setAdapter(new ArrayAdapter<>(requireContext(), android.R.layout.simple_spinner_item, PAYMENT_METHODS)); @@ -91,89 +102,82 @@ public class SaleDetailFragment extends Fragment { } private void loadStores() { - // Hardcoded since store endpoint is admin only - storeList = new ArrayList<>(); - storeList.add(new StoreDTO(1L, "Downtown Branch")); - List names = new ArrayList<>(); - names.add("-- Select Store --"); - names.add("Downtown Branch"); - binding.spinnerSaleStore.setAdapter(new ArrayAdapter<>(requireContext(), - android.R.layout.simple_spinner_item, names)); + + storeViewModel.getAllStores(0, 50).observe(getViewLifecycleOwner(), resource -> { + if (resource != null && resource.status == com.example.petstoremobile.utils.Resource.Status.SUCCESS && resource.data != null) { + storeList = resource.data.getContent(); + List names = new ArrayList<>(); + names.add("-- Select Store --"); + for (StoreDTO s : storeList) names.add(s.getStoreName()); + if (binding != null) { + binding.spinnerSaleStore.setAdapter(new ArrayAdapter<>(requireContext(), + android.R.layout.simple_spinner_item, names)); + } + } else if (storeList.isEmpty()) { + // Fallback if failed or empty + storeList = new ArrayList<>(); + storeList.add(new StoreDTO(1L, "Downtown Branch")); + List names = new ArrayList<>(); + names.add("-- Select Store --"); + names.add("Downtown Branch"); + if (binding != null) { + binding.spinnerSaleStore.setAdapter(new ArrayAdapter<>(requireContext(), + android.R.layout.simple_spinner_item, names)); + } + } + }); } private void loadCustomers() { - RetrofitClient.getCustomerApi(requireContext()).getAllCustomers(0, 200) - .enqueue(new Callback>() { - public void onResponse(Call> c, - Response> r) { - if (r.isSuccessful() && r.body() != null) { - customerList = r.body().getContent(); - List names = new ArrayList<>(); - names.add("-- No Customer --"); - for (CustomerDTO cu : customerList) - names.add(cu.getFirstName() + " " + cu.getLastName()); - if (binding != null) { - binding.spinnerSaleCustomer.setAdapter(new ArrayAdapter<>(requireContext(), - android.R.layout.simple_spinner_item, names)); - } - } - } - - public void onFailure(Call> c, Throwable t) { - Log.e("SaleDetail", "Customer load failed: " + t.getMessage()); - } - }); + customerViewModel.getAllCustomers(0, 200).observe(getViewLifecycleOwner(), resource -> { + if (resource != null && resource.status == com.example.petstoremobile.utils.Resource.Status.SUCCESS && resource.data != null) { + customerList = resource.data.getContent(); + List names = new ArrayList<>(); + names.add("-- No Customer --"); + for (CustomerDTO cu : customerList) + names.add(cu.getFirstName() + " " + cu.getLastName()); + if (binding != null) { + binding.spinnerSaleCustomer.setAdapter(new ArrayAdapter<>(requireContext(), + android.R.layout.simple_spinner_item, names)); + } + } + }); } private void loadProducts() { - RetrofitClient.getProductApi(requireContext()).getAllProducts(null, null, 0, 200, null) - .enqueue(new Callback>() { - public void onResponse(Call> c, - Response> r) { - if (r.isSuccessful() && r.body() != null) { - productList = r.body().getContent(); - List names = new ArrayList<>(); - names.add("-- Select Product --"); - for (ProductDTO p : productList) - names.add(p.getProdName()); - if (binding != null) { - binding.spinnerSaleProduct.setAdapter(new ArrayAdapter<>(requireContext(), - android.R.layout.simple_spinner_item, names)); - } - } - } - - public void onFailure(Call> c, Throwable t) { - Log.e("SaleDetail", "Product load failed: " + t.getMessage()); - } - }); + productViewModel.getAllProducts(null, null, 0, 200, null).observe(getViewLifecycleOwner(), resource -> { + if (resource != null && resource.status == com.example.petstoremobile.utils.Resource.Status.SUCCESS && resource.data != null) { + productList = resource.data.getContent(); + List names = new ArrayList<>(); + names.add("-- Select Product --"); + for (ProductDTO p : productList) + names.add(p.getProdName()); + if (binding != null) { + binding.spinnerSaleProduct.setAdapter(new ArrayAdapter<>(requireContext(), + android.R.layout.simple_spinner_item, names)); + } + } + }); } private void loadSaleDetails() { - RetrofitClient.getSaleApi(requireContext()).getSaleById(saleId) - .enqueue(new Callback() { - public void onResponse(Call c, Response r) { - if (r.isSuccessful() && r.body() != null) { - SaleDTO sale = r.body(); - if (binding != null) { - binding.tvSaleDetailTotal.setText("Total: $" + sale.getTotalAmount()); - // Display items - if (sale.getItems() != null) { - binding.llSaleItems.removeAllViews(); - for (SaleDTO.SaleItemDTO item : sale.getItems()) { - addItemRow(item.getProductName(), - Math.abs(item.getQuantity()), - item.getUnitPrice()); - } - } - } + saleViewModel.getSaleById(saleId).observe(getViewLifecycleOwner(), resource -> { + if (resource != null && resource.status == com.example.petstoremobile.utils.Resource.Status.SUCCESS && resource.data != null) { + SaleDTO sale = resource.data; + if (binding != null) { + binding.tvSaleDetailTotal.setText("Total: $" + sale.getTotalAmount()); + // Display items + if (sale.getItems() != null) { + binding.llSaleItems.removeAllViews(); + for (SaleDTO.SaleItemDTO item : sale.getItems()) { + addItemRow(item.getProductName(), + Math.abs(item.getQuantity()), + item.getUnitPrice()); } } - - public void onFailure(Call c, Throwable t) { - Log.e("SaleDetail", "Load failed: " + t.getMessage()); - } - }); + } + } + }); } private void setupAddItem() { @@ -214,6 +218,7 @@ public class SaleDetailFragment extends Fragment { } private void addItemRow(String name, int qty, BigDecimal price) { + if (getContext() == null) return; LinearLayout row = new LinearLayout(getContext()); row.setOrientation(LinearLayout.HORIZONTAL); row.setPadding(0, 8, 0, 8); @@ -263,7 +268,7 @@ public class SaleDetailFragment extends Fragment { return; } - StoreDTO store = storeList.get(0); // only one store + StoreDTO store = storeList.get(binding.spinnerSaleStore.getSelectedItemPosition() - 1); String payment = PAYMENT_METHODS[binding.spinnerPaymentMethod.getSelectedItemPosition()]; // Optional customer @@ -281,29 +286,20 @@ public class SaleDetailFragment extends Fragment { null, customerId); - RetrofitClient.getSaleApi(requireContext()).createSale(dto) - .enqueue(new Callback() { - public void onResponse(Call c, Response r) { - if (r.isSuccessful()) { - Toast.makeText(getContext(), "Sale saved!", Toast.LENGTH_SHORT).show(); - navigateBack(); - } else { - try { - String err = r.errorBody().string(); - Log.e("SALE_SAVE", "Error: " + err); - Toast.makeText(getContext(), "Error " + r.code() + ": " + err, - Toast.LENGTH_LONG).show(); - } catch (Exception e) { - Log.e("SALE_SAVE", "Failed to read error"); - } - } - } - - public void onFailure(Call c, Throwable t) { - Log.e("SALE_SAVE", "Failure: " + t.getMessage()); - Toast.makeText(getContext(), "Network error", Toast.LENGTH_SHORT).show(); - } - }); + saleViewModel.createSale(dto).observe(getViewLifecycleOwner(), resource -> { + if (resource != null) { + switch (resource.status) { + case SUCCESS: + Toast.makeText(getContext(), "Sale saved!", Toast.LENGTH_SHORT).show(); + navigateBack(); + break; + case ERROR: + Log.e("SALE_SAVE", "Error: " + resource.message); + Toast.makeText(getContext(), "Error: " + resource.message, Toast.LENGTH_LONG).show(); + break; + } + } + }); } private void showRefundDialog() { 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 1200403c..508282bc 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 @@ -7,17 +7,19 @@ import android.widget.*; import androidx.annotation.NonNull; import androidx.appcompat.app.AlertDialog; import androidx.fragment.app.Fragment; +import androidx.lifecycle.ViewModelProvider; import androidx.navigation.fragment.NavHostFragment; import com.example.petstoremobile.R; -import com.example.petstoremobile.api.EmployeeApi; -import com.example.petstoremobile.api.RetrofitClient; import com.example.petstoremobile.databinding.FragmentStaffDetailBinding; import com.example.petstoremobile.dtos.EmployeeDTO; -import retrofit2.*; +import com.example.petstoremobile.viewmodels.EmployeeViewModel; +import dagger.hilt.android.AndroidEntryPoint; +@AndroidEntryPoint public class StaffDetailFragment extends Fragment { private FragmentStaffDetailBinding binding; + private EmployeeViewModel employeeViewModel; private long employeeId = -1; private boolean isEditing = false; @@ -28,6 +30,7 @@ public class StaffDetailFragment extends Fragment { public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { binding = FragmentStaffDetailBinding.inflate(inflater, container, false); + employeeViewModel = new ViewModelProvider(this).get(EmployeeViewModel.class); setupSpinners(); handleArguments(); @@ -118,34 +121,35 @@ public class StaffDetailFragment extends Fragment { active ); - EmployeeApi api = RetrofitClient.getEmployeeApi(requireContext()); if (isEditing && employeeId > 0) { - api.updateEmployee(employeeId, dto).enqueue(simpleCallback("Updated successfully")); - } else { - api.createEmployee(dto).enqueue(simpleCallback("Staff account created")); - } - } - - private Callback simpleCallback(String msg) { - return new Callback<>() { - public void onResponse(Call c, Response r) { - if (r.isSuccessful()) { - Toast.makeText(getContext(), msg, Toast.LENGTH_SHORT).show(); - navigateBack(); - } else { - try { - String err = r.errorBody().string(); - Toast.makeText(getContext(), "Error " + r.code() + ": " + err, - Toast.LENGTH_LONG).show(); - } catch (Exception e) { - Log.e("STAFF_SAVE", "Failed to read error"); + employeeViewModel.updateEmployee(employeeId, dto).observe(getViewLifecycleOwner(), resource -> { + if (resource != null) { + switch (resource.status) { + case SUCCESS: + Toast.makeText(getContext(), "Updated successfully", Toast.LENGTH_SHORT).show(); + navigateBack(); + break; + case ERROR: + Toast.makeText(getContext(), "Error: " + resource.message, Toast.LENGTH_LONG).show(); + break; } } - } - public void onFailure(Call c, Throwable t) { - Toast.makeText(getContext(), "Network error", Toast.LENGTH_SHORT).show(); - } - }; + }); + } else { + employeeViewModel.createEmployee(dto).observe(getViewLifecycleOwner(), resource -> { + if (resource != null) { + switch (resource.status) { + case SUCCESS: + Toast.makeText(getContext(), "Staff account created", Toast.LENGTH_SHORT).show(); + navigateBack(); + break; + case ERROR: + Toast.makeText(getContext(), "Error: " + resource.message, Toast.LENGTH_LONG).show(); + break; + } + } + }); + } } private void confirmDelete() { @@ -153,17 +157,19 @@ public class StaffDetailFragment extends Fragment { .setTitle("Delete Staff Account?") .setMessage("This will permanently delete this staff account.") .setPositiveButton("Yes", (d, w) -> - RetrofitClient.getEmployeeApi(requireContext()) - .deleteEmployee(employeeId) - .enqueue(new Callback() { - public void onResponse(Call c, Response r) { + employeeViewModel.deleteEmployee(employeeId).observe(getViewLifecycleOwner(), resource -> { + if (resource != null) { + switch (resource.status) { + case SUCCESS: navigateBack(); - } - public void onFailure(Call c, Throwable t) { - Toast.makeText(getContext(), "Delete failed", + break; + case ERROR: + Toast.makeText(getContext(), "Delete failed: " + resource.message, Toast.LENGTH_SHORT).show(); - } - })) + break; + } + } + })) .setNegativeButton("No", null).show(); }