diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts index ef712a40..87add966 100644 --- a/android/app/build.gradle.kts +++ b/android/app/build.gradle.kts @@ -3,6 +3,7 @@ import java.util.Properties plugins { alias(libs.plugins.android.application) alias(libs.plugins.hilt) + alias(libs.plugins.navigation.safeargs) } val localProperties = Properties().apply { @@ -64,6 +65,9 @@ dependencies { implementation(libs.hilt.android) annotationProcessor(libs.hilt.compiler) + implementation(libs.navigation.fragment) + implementation(libs.navigation.ui) + implementation("com.squareup.retrofit2:retrofit:2.9.0") implementation("com.squareup.retrofit2:converter-gson:2.9.0") implementation("com.squareup.okhttp3:logging-interceptor:4.12.0") 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 513c3683..09bcea9d 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 @@ -15,12 +15,11 @@ import androidx.core.content.ContextCompat; import androidx.core.graphics.Insets; import androidx.core.view.ViewCompat; import androidx.core.view.WindowInsetsCompat; -import androidx.fragment.app.Fragment; +import androidx.navigation.NavController; +import androidx.navigation.fragment.NavHostFragment; +import androidx.navigation.ui.NavigationUI; import com.example.petstoremobile.R; -import com.example.petstoremobile.fragments.ChatFragment; -import com.example.petstoremobile.fragments.ListFragment; -import com.example.petstoremobile.fragments.ProfileFragment; import com.example.petstoremobile.services.ChatNotificationService; import com.google.android.material.bottomnavigation.BottomNavigationView; @@ -29,6 +28,7 @@ import dagger.hilt.android.AndroidEntryPoint; @AndroidEntryPoint public class HomeActivity extends AppCompatActivity { private BottomNavigationView bottomNav; + private NavController navController; // Launcher to ask for notification permission private final ActivityResultLauncher requestPermissionLauncher = @@ -52,66 +52,52 @@ public class HomeActivity extends AppCompatActivity { //get the bottom navbar from the layout bottomNav = findViewById(R.id.bottom_navigation); - + + // Initialize Navigation Component + NavHostFragment navHostFragment = (NavHostFragment) getSupportFragmentManager() + .findFragmentById(R.id.nav_host_fragment); + if (navHostFragment != null) { + navController = navHostFragment.getNavController(); + NavigationUI.setupWithNavController(bottomNav, navController); + } + //load the list fragment by default if it's a fresh start if (savedInstanceState == null) { handleIntent(getIntent()); } - //when an item in the bottom bar is selected, load the corresponding fragment - bottomNav.setOnItemSelectedListener(item -> { - if (item.getItemId() == R.id.nav_list) { - loadFragment(new ListFragment()); - return true; - } else if (item.getItemId() == R.id.nav_chat) { - loadFragment(new ChatFragment()); - return true; - } else if (item.getItemId() == R.id.nav_profile) { - loadFragment(new ProfileFragment()); - return true; - } - return false; - }); - // Start the notification service and request for notification permission startNotificationService(); requestNotificationPermission(); } - // Handle new intents when the activity is already running, - // like clicking a notification while the app is in use @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); handleIntent(intent); } - // Helper function to process intents for navigation. - // like clicking a notification or just launching the app from a fresh start private void handleIntent(Intent intent) { if (intent != null && "chat".equals(intent.getStringExtra("navigate_to"))) { - ChatFragment chatFragment = new ChatFragment(); + Bundle args = new Bundle(); if (intent.hasExtra("conversation_id")) { - Bundle args = new Bundle(); args.putLong("conversation_id", intent.getLongExtra("conversation_id", -1)); - chatFragment.setArguments(args); } - loadFragment(chatFragment); - bottomNav.setSelectedItemId(R.id.nav_chat); - } else { - loadFragment(new ListFragment()); - bottomNav.setSelectedItemId(R.id.nav_list); + // Use NavController to navigate + if (navController != null) { + navController.navigate(R.id.nav_chat, args); + } } } - // Helper function to start the notification service in the background + // Function to start the notification service in the background // to receive notifications when a new conversation is created private void startNotificationService() { Intent serviceIntent = new Intent(this, ChatNotificationService.class); startService(serviceIntent); } - //Helper function to request for notification permission + //Function to request for notification permission private void requestNotificationPermission() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) { @@ -119,12 +105,4 @@ public class HomeActivity extends AppCompatActivity { } } } - - //Helper function to load a fragment - private void loadFragment(Fragment fragment) { - getSupportFragmentManager() - .beginTransaction() - .replace(R.id.fragment_container, fragment) - .commit(); - } } \ No newline at end of file diff --git a/android/app/src/main/java/com/example/petstoremobile/adapters/PetAdapter.java b/android/app/src/main/java/com/example/petstoremobile/adapters/PetAdapter.java index d5008aff..1f1c5120 100644 --- a/android/app/src/main/java/com/example/petstoremobile/adapters/PetAdapter.java +++ b/android/app/src/main/java/com/example/petstoremobile/adapters/PetAdapter.java @@ -11,6 +11,8 @@ import androidx.recyclerview.widget.RecyclerView; import com.bumptech.glide.Glide; import com.bumptech.glide.load.engine.DiskCacheStrategy; +import com.bumptech.glide.load.model.GlideUrl; +import com.bumptech.glide.load.model.LazyHeaders; import com.example.petstoremobile.R; import com.example.petstoremobile.api.PetApi; import com.example.petstoremobile.dtos.PetDTO; @@ -21,6 +23,7 @@ public class PetAdapter extends RecyclerView.Adapter { private List petList; private OnPetClickListener petClickListener; private String baseUrl; + private String token; // Interface for pet click on recycler view public interface OnPetClickListener { @@ -37,6 +40,10 @@ public class PetAdapter extends RecyclerView.Adapter { this.baseUrl = baseUrl; } + public void setToken(String token) { + this.token = token; + } + // Get the controls of each row in recycler view public static class PetViewHolder extends RecyclerView.ViewHolder { TextView tvPetName, tvPetSpeciesBreed, tvPetAge, tvPetPrice, tvPetStatus; @@ -89,11 +96,18 @@ public class PetAdapter extends RecyclerView.Adapter { // Load pet image using Glide with circle crop if (baseUrl != null) { String imageUrl = baseUrl + String.format(PetApi.PET_IMAGE_PATH, pet.getPetId()); + + Object loadTarget = imageUrl; + if (token != null) { + loadTarget = new GlideUrl(imageUrl, new LazyHeaders.Builder() + .addHeader("Authorization", "Bearer " + token) + .build()); + } + Glide.with(holder.itemView.getContext()) - .load(imageUrl) + .load(loadTarget) .circleCrop() - .diskCacheStrategy(DiskCacheStrategy.NONE) - .skipMemoryCache(true) + .diskCacheStrategy(DiskCacheStrategy.ALL) // Changed to ALL for better performance .placeholder(R.drawable.placeholder) .error(R.drawable.placeholder) .into(holder.ivPetProfile); 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 5bcc4d3a..2363a682 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 @@ -8,6 +8,8 @@ import androidx.recyclerview.widget.RecyclerView; import com.bumptech.glide.Glide; import com.bumptech.glide.load.engine.DiskCacheStrategy; +import com.bumptech.glide.load.model.GlideUrl; +import com.bumptech.glide.load.model.LazyHeaders; import com.example.petstoremobile.R; import com.example.petstoremobile.api.ProductApi; import com.example.petstoremobile.dtos.ProductDTO; @@ -18,6 +20,7 @@ public class ProductAdapter extends RecyclerView.Adapter productList; private OnProductClickListener listener; private String baseUrl; + private String token; public interface OnProductClickListener { void onProductClick(int position); @@ -32,6 +35,10 @@ public class ProductAdapter extends RecyclerView.Adapter { - loadFragment(new PetFragment()); - drawerLayout.closeDrawers(); - }); - - //Services - drawerServices.setOnClickListener(v -> { - loadFragment(new ServiceFragment()); - drawerLayout.closeDrawers(); - }); - - //Suppliers - drawerSuppliers.setOnClickListener(v -> { - loadFragment(new SupplierFragment()); - drawerLayout.closeDrawers(); - }); - - //Adoptions - - drawerAdoptions.setOnClickListener(v -> { - loadFragment(new AdoptionFragment()); - drawerLayout.closeDrawers(); - }); - - //Appointment - drawerAppointments.setOnClickListener(v -> { - loadFragment(new AppointmentFragment()); - drawerLayout.closeDrawers(); - }); - - //Inventory - drawerInventory.setOnClickListener(v -> { - loadFragment(new InventoryFragment()); - drawerLayout.closeDrawers(); - }); - - //Products - drawerProducts.setOnClickListener(v -> { - loadFragment(new ProductFragment()); - drawerLayout.closeDrawers(); - }); - - //ProductSupplier - - drawerProductSupplier.setOnClickListener(v -> { - loadFragment(new ProductSupplierFragment()); - drawerLayout.closeDrawers(); - }); - - //Purchase - - drawerPurchaseOrderView.setOnClickListener(v -> { - loadFragment(new PurchaseOrderFragment()); - drawerLayout.closeDrawers(); - }); - - //Sale - - drawerSale.setOnClickListener(v -> { - loadFragment(new SaleFragment()); - drawerLayout.closeDrawers(); - }); + drawerPets.setOnClickListener(v -> navigateTo(R.id.nav_pet)); + drawerServices.setOnClickListener(v -> navigateTo(R.id.nav_service)); + drawerSuppliers.setOnClickListener(v -> navigateTo(R.id.nav_supplier)); + drawerAdoptions.setOnClickListener(v -> navigateTo(R.id.nav_adoption)); + drawerAppointments.setOnClickListener(v -> navigateTo(R.id.nav_appointment)); + drawerInventory.setOnClickListener(v -> navigateTo(R.id.nav_inventory)); + drawerProducts.setOnClickListener(v -> navigateTo(R.id.nav_product)); + drawerProductSupplier.setOnClickListener(v -> navigateTo(R.id.nav_product_supplier)); + drawerPurchaseOrderView.setOnClickListener(v -> navigateTo(R.id.nav_purchase_order)); + drawerSale.setOnClickListener(v -> navigateTo(R.id.nav_sale)); return view; } + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + NavHostFragment navHostFragment = (NavHostFragment) getChildFragmentManager() + .findFragmentById(R.id.inner_nav_host_fragment); + if (navHostFragment != null) { + innerNavController = navHostFragment.getNavController(); + } + } + + private void navigateTo(int destinationId) { + if (innerNavController != null) { + innerNavController.navigate(destinationId); + } + drawerLayout.closeDrawers(); + } + //helper function to open the drawer public void openDrawer() { drawerLayout.openDrawer(GravityCompat.START); } - - // helper function to load the fragment into the display - public void loadFragment(Fragment fragment) { - getChildFragmentManager() - .beginTransaction() - .replace(R.id.inner_fragment_container, fragment) - .addToBackStack(null) - .commit(); - } -} \ No newline at end of file +} 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 06757a32..92c8cdea 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 @@ -8,6 +8,7 @@ import android.view.*; import android.widget.*; import androidx.annotation.NonNull; import androidx.fragment.app.Fragment; +import androidx.navigation.fragment.NavHostFragment; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; @@ -17,7 +18,6 @@ import com.example.petstoremobile.api.AdoptionApi; import com.example.petstoremobile.dtos.AdoptionDTO; import com.example.petstoremobile.dtos.PageResponse; import com.example.petstoremobile.fragments.ListFragment; -import com.example.petstoremobile.fragments.listfragments.detailfragments.AdoptionDetailFragment; import com.example.petstoremobile.utils.EventDecorator; import com.google.android.material.floatingactionbutton.FloatingActionButton; import com.prolificinteractive.materialcalendarview.CalendarDay; @@ -68,8 +68,13 @@ public class AdoptionFragment extends Fragment implements AdoptionAdapter.OnAdop fab.setOnClickListener(v -> openDetail(-1)); hamburger.setOnClickListener(v -> { - ListFragment lf = (ListFragment) getParentFragment(); - if (lf != null) lf.openDrawer(); + Fragment parent = getParentFragment(); + if (parent != null) { + Fragment grandParent = parent.getParentFragment(); + if (grandParent instanceof ListFragment) { + ((ListFragment) grandParent).openDrawer(); + } + } }); btnToggleCalendarMode.setOnClickListener(v -> toggleCalendarMode()); @@ -197,7 +202,6 @@ public class AdoptionFragment extends Fragment implements AdoptionAdapter.OnAdop } private void openDetail(int position) { - AdoptionDetailFragment detail = new AdoptionDetailFragment(); Bundle args = new Bundle(); if (position != -1) { @@ -209,11 +213,9 @@ public class AdoptionFragment extends Fragment implements AdoptionAdapter.OnAdop args.putString("adoptionStatus", a.getAdoptionStatus()); } - detail.setArguments(args); - ListFragment lf = (ListFragment) getParentFragment(); - if (lf != null) lf.loadFragment(detail); + NavHostFragment.findNavController(this).navigate(R.id.nav_adoption_detail, args); } @Override public void onAdoptionClick(int position) { openDetail(position); } -} \ No newline at end of file +} 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 83115a3b..3f50f7cc 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 @@ -5,6 +5,7 @@ import android.os.Bundle; import androidx.annotation.NonNull; import androidx.fragment.app.Fragment; +import androidx.navigation.fragment.NavHostFragment; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; @@ -28,7 +29,6 @@ import com.example.petstoremobile.dtos.ServiceDTO; import com.example.petstoremobile.dtos.PageResponse; import com.example.petstoremobile.dtos.PetDTO; import com.example.petstoremobile.fragments.ListFragment; -import com.example.petstoremobile.fragments.listfragments.detailfragments.AppointmentDetailFragment; import com.example.petstoremobile.utils.EventDecorator; import com.google.android.material.floatingactionbutton.FloatingActionButton; import com.prolificinteractive.materialcalendarview.CalendarDay; @@ -96,9 +96,13 @@ public class AppointmentFragment extends Fragment implements AppointmentAdapter. fabAdd.setOnClickListener(v -> openAppointmentDetails(-1)); hamburger.setOnClickListener(v -> { - ListFragment listFragment = (ListFragment) getParentFragment(); - if (listFragment != null) - listFragment.openDrawer(); + Fragment parent = getParentFragment(); + if (parent != null) { + Fragment grandParent = parent.getParentFragment(); + if (grandParent instanceof ListFragment) { + ((ListFragment) grandParent).openDrawer(); + } + } }); btnToggleCalendarMode.setOnClickListener(v -> toggleCalendarMode()); @@ -205,7 +209,6 @@ public class AppointmentFragment extends Fragment implements AppointmentAdapter. } private void openAppointmentDetails(int position) { - AppointmentDetailFragment detailFragment = new AppointmentDetailFragment(); Bundle args = new Bundle(); if (position != -1) { @@ -221,9 +224,7 @@ public class AppointmentFragment extends Fragment implements AppointmentAdapter. if (a.getStoreId() != null) args.putLong("storeId", a.getStoreId()); } - detailFragment.setArguments(args); - ListFragment lf = (ListFragment) getParentFragment(); - if (lf != null) lf.loadFragment(detailFragment); + NavHostFragment.findNavController(this).navigate(R.id.nav_appointment_detail, args); } public void onAppointmentSaved(int position, AppointmentDTO appointment) { loadAppointmentData(); @@ -333,4 +334,4 @@ public class AppointmentFragment extends Fragment implements AppointmentAdapter. recyclerView.setLayoutManager(new LinearLayoutManager(getContext())); recyclerView.setAdapter(adapter); } -} \ No newline at end of file +} 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 ce93ca54..0bfe389b 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 @@ -17,7 +17,10 @@ import android.widget.Spinner; import android.widget.TextView; import android.widget.Toast; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; +import androidx.navigation.fragment.NavHostFragment; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; @@ -32,8 +35,6 @@ import com.example.petstoremobile.dtos.CategoryDTO; import com.example.petstoremobile.dtos.InventoryDTO; import com.example.petstoremobile.dtos.PageResponse; import com.example.petstoremobile.fragments.ListFragment; -import com.example.petstoremobile.fragments.listfragments.detailfragments.InventoryDetailFragment; -import com.google.android.material.floatingactionbutton.FloatingActionButton; import java.util.ArrayList; import java.util.List; @@ -100,9 +101,13 @@ public class InventoryFragment extends Fragment implements InventoryAdapter.OnIn .setOnClickListener(v -> openDetail(null)); hamburger.setOnClickListener(v -> { - ListFragment lf = (ListFragment) getParentFragment(); - if (lf != null) - lf.openDrawer(); + Fragment parent = getParentFragment(); + if (parent != null) { + Fragment grandParent = parent.getParentFragment(); + if (grandParent instanceof ListFragment) { + ((ListFragment) grandParent).openDrawer(); + } + } }); btnBulkDelete.setOnClickListener(v -> confirmBulkDelete()); @@ -174,7 +179,8 @@ public class InventoryFragment extends Fragment implements InventoryAdapter.OnIn private void setupSearch(View view) { etSearch = view.findViewById(R.id.etSearchInventory); etSearch.addTextChangedListener(new TextWatcher() { - @Override public void beforeTextChanged(CharSequence s, int i, int i1, int i2) { + @Override + public void beforeTextChanged(CharSequence s, int i, int i1, int i2) { } @Override @@ -332,7 +338,6 @@ public class InventoryFragment extends Fragment implements InventoryAdapter.OnIn // Navigation private void openDetail(InventoryDTO inv) { - InventoryDetailFragment detail = new InventoryDetailFragment(); Bundle args = new Bundle(); if (inv != null) { @@ -343,12 +348,7 @@ public class InventoryFragment extends Fragment implements InventoryAdapter.OnIn args.putInt("quantity", inv.getQuantity() != null ? inv.getQuantity() : 0); } - detail.setArguments(args); - detail.setInventoryFragment(this); - - ListFragment lf = (ListFragment) getParentFragment(); - if (lf != null) - lf.loadFragment(detail); + NavHostFragment.findNavController(this).navigate(R.id.nav_inventory_detail, args); } public void onInventoryChanged() { 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 693e261f..ac456828 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 @@ -2,7 +2,10 @@ package com.example.petstoremobile.fragments.listfragments; import android.os.Bundle; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; +import androidx.navigation.fragment.NavHostFragment; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; @@ -26,8 +29,6 @@ import com.example.petstoremobile.api.PetApi; import com.example.petstoremobile.dtos.PageResponse; import com.example.petstoremobile.dtos.PetDTO; import com.example.petstoremobile.fragments.ListFragment; -import com.example.petstoremobile.fragments.listfragments.detailfragments.PetDetailFragment; -import com.example.petstoremobile.fragments.listfragments.listprofilefragments.PetProfileFragment; import com.google.android.material.floatingactionbutton.FloatingActionButton; import java.util.ArrayList; @@ -73,10 +74,12 @@ public class PetFragment extends Fragment implements PetAdapter.OnPetClickListen //Make the hamburger button open the drawer from listFragment hamburger.setOnClickListener(v -> { - ListFragment listFragment = (ListFragment) getParentFragment(); - //if list fragment is found then use its helper function to open the drawer - if (listFragment != null) { - listFragment.openDrawer(); + Fragment parent = getParentFragment(); + if (parent != null) { + Fragment grandParent = parent.getParentFragment(); + if (grandParent instanceof ListFragment) { + ((ListFragment) grandParent).openDrawer(); + } } }); @@ -150,8 +153,6 @@ public class PetFragment extends Fragment implements PetAdapter.OnPetClickListen //Open pet profile private void openPetProfile(int position) { - PetProfileFragment profileFragment = new PetProfileFragment(); - //Make a bundle to pass data to the profile fragment Bundle args = new Bundle(); PetDTO pet = filteredList.get(position); @@ -168,25 +169,12 @@ public class PetFragment extends Fragment implements PetAdapter.OnPetClickListen args.putDouble("petPrice", 0.0); } - //send the bundle to the profile fragment to display - profileFragment.setArguments(args); - - //get ListFragment to load the the pet profile view - ListFragment listFragment = (ListFragment) getParentFragment(); - if (listFragment != null) { - listFragment.loadFragment(profileFragment); - } + NavHostFragment.findNavController(this).navigate(R.id.nav_pet_profile, args); } //Open the pet detail view for adding private void openPetDetails(int position) { - PetDetailFragment detailFragment = new PetDetailFragment(); - - //get ListFragment to load the detail view - ListFragment listFragment = (ListFragment) getParentFragment(); - if (listFragment != null) { - listFragment.loadFragment(detailFragment); - } + NavHostFragment.findNavController(this).navigate(R.id.nav_pet_detail); } // Called by PetAdapter when a row is clicked to open the details view @@ -236,4 +224,4 @@ public class PetFragment extends Fragment implements PetAdapter.OnPetClickListen recyclerView.setLayoutManager(new LinearLayoutManager(getContext())); recyclerView.setAdapter(adapter); } -} \ No newline at end of file +} 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 ce15a7e8..16d6347f 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 @@ -6,20 +6,22 @@ import android.util.Log; import android.view.*; import android.widget.*; import androidx.fragment.app.Fragment; +import androidx.navigation.fragment.NavHostFragment; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; import com.example.petstoremobile.R; import com.example.petstoremobile.adapters.ProductAdapter; import com.example.petstoremobile.api.ProductApi; +import com.example.petstoremobile.api.auth.TokenManager; import com.example.petstoremobile.dtos.PageResponse; import com.example.petstoremobile.dtos.ProductDTO; import com.example.petstoremobile.fragments.ListFragment; -import com.example.petstoremobile.fragments.listfragments.detailfragments.ProductDetailFragment; import com.google.android.material.floatingactionbutton.FloatingActionButton; import java.util.*; import javax.inject.Inject; +import javax.inject.Named; import dagger.hilt.android.AndroidEntryPoint; import retrofit2.*; @@ -34,6 +36,8 @@ public class ProductFragment extends Fragment implements ProductAdapter.OnProduc private EditText etSearch; @Inject ProductApi api; + @Inject @Named("baseUrl") String baseUrl; + @Inject TokenManager tokenManager; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, @@ -51,8 +55,13 @@ public class ProductFragment extends Fragment implements ProductAdapter.OnProduc ImageButton hamburger = view.findViewById(R.id.btnHamburgerProduct); hamburger.setOnClickListener(v -> { - ListFragment lf = (ListFragment) getParentFragment(); - if (lf != null) lf.openDrawer(); + Fragment parent = getParentFragment(); + if (parent != null) { + Fragment grandParent = parent.getParentFragment(); + if (grandParent instanceof ListFragment) { + ((ListFragment) grandParent).openDrawer(); + } + } }); return view; @@ -61,6 +70,8 @@ public class ProductFragment extends Fragment implements ProductAdapter.OnProduc private void setupRecyclerView(View view) { RecyclerView rv = view.findViewById(R.id.recyclerViewProducts); adapter = new ProductAdapter(filteredList, this); + adapter.setBaseUrl(baseUrl); + adapter.setToken(tokenManager.getToken()); rv.setLayoutManager(new LinearLayoutManager(getContext())); rv.setAdapter(adapter); } @@ -122,7 +133,6 @@ public class ProductFragment extends Fragment implements ProductAdapter.OnProduc } private void openDetail(int position) { - ProductDetailFragment detail = new ProductDetailFragment(); Bundle args = new Bundle(); if (position != -1) { ProductDTO p = filteredList.get(position); @@ -132,11 +142,9 @@ public class ProductFragment extends Fragment implements ProductAdapter.OnProduc args.putString("prodPrice", p.getProdPrice() != null ? p.getProdPrice().toString() : ""); args.putLong("categoryId", p.getCategoryId() != null ? p.getCategoryId() : -1); } - detail.setArguments(args); - ListFragment lf = (ListFragment) getParentFragment(); - if (lf != null) lf.loadFragment(detail); + NavHostFragment.findNavController(this).navigate(R.id.nav_product_detail, args); } @Override public void onProductClick(int position) { openDetail(position); } -} \ No newline at end of file +} 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 0f76041e..18d97c9d 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 @@ -6,6 +6,7 @@ import android.util.Log; import android.view.*; import android.widget.*; import androidx.fragment.app.Fragment; +import androidx.navigation.fragment.NavHostFragment; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; @@ -51,8 +52,13 @@ public class ProductSupplierFragment extends Fragment ImageButton hamburger = view.findViewById(R.id.btnHamburgerPS); hamburger.setOnClickListener(v -> { - ListFragment lf = (ListFragment) getParentFragment(); - if (lf != null) lf.openDrawer(); + Fragment parent = getParentFragment(); + if (parent != null) { + Fragment grandParent = parent.getParentFragment(); + if (grandParent instanceof ListFragment) { + ((ListFragment) grandParent).openDrawer(); + } + } }); return view; @@ -121,7 +127,6 @@ public class ProductSupplierFragment extends Fragment } private void openDetail(int position) { - ProductSupplierDetailFragment detail = new ProductSupplierDetailFragment(); Bundle args = new Bundle(); if (position != -1) { ProductSupplierDTO ps = filteredList.get(position); @@ -131,9 +136,7 @@ public class ProductSupplierFragment extends Fragment args.putString("supplierName", ps.getSupplierName()); args.putString("cost", ps.getCost() != null ? ps.getCost().toString() : ""); } - detail.setArguments(args); - ListFragment lf = (ListFragment) getParentFragment(); - if (lf != null) lf.loadFragment(detail); + NavHostFragment.findNavController(this).navigate(R.id.nav_product_supplier_detail, args); } @Override 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 4840b549..9a7226a8 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 @@ -6,6 +6,7 @@ import android.util.Log; import android.view.*; import android.widget.*; import androidx.fragment.app.Fragment; +import androidx.navigation.fragment.NavHostFragment; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; @@ -15,7 +16,6 @@ import com.example.petstoremobile.api.PurchaseOrderApi; import com.example.petstoremobile.dtos.PageResponse; import com.example.petstoremobile.dtos.PurchaseOrderDTO; import com.example.petstoremobile.fragments.ListFragment; -import com.example.petstoremobile.fragments.listfragments.detailfragments.PurchaseOrderDetailFragment; import java.util.*; import javax.inject.Inject; @@ -47,9 +47,13 @@ public class PurchaseOrderFragment extends Fragment ImageButton hamburger = view.findViewById(R.id.btnHamburgerPO); hamburger.setOnClickListener(v -> { - ListFragment lf = (ListFragment) getParentFragment(); - if (lf != null) - lf.openDrawer(); + Fragment parent = getParentFragment(); + if (parent != null) { + Fragment grandParent = parent.getParentFragment(); + if (grandParent instanceof ListFragment) { + ((ListFragment) grandParent).openDrawer(); + } + } }); return view; @@ -126,17 +130,13 @@ public class PurchaseOrderFragment extends Fragment } private void openDetail(int position) { - PurchaseOrderDetailFragment detail = new PurchaseOrderDetailFragment(); Bundle args = new Bundle(); PurchaseOrderDTO po = filteredList.get(position); args.putLong("purchaseOrderId", po.getPurchaseOrderId()); args.putString("supplierName", po.getSupplierName()); args.putString("orderDate", po.getOrderDate()); args.putString("status", po.getStatus()); - detail.setArguments(args); - ListFragment lf = (ListFragment) getParentFragment(); - if (lf != null) - lf.loadFragment(detail); + NavHostFragment.findNavController(this).navigate(R.id.nav_purchase_order_detail, args); } @Override 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 74b8c4ef..9ea74d19 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 @@ -2,6 +2,7 @@ package com.example.petstoremobile.fragments.listfragments; import android.os.Bundle; import androidx.fragment.app.Fragment; +import androidx.navigation.fragment.NavHostFragment; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; @@ -17,7 +18,6 @@ import com.example.petstoremobile.R; import com.example.petstoremobile.adapters.SaleAdapter; import com.example.petstoremobile.api.SaleApi; import com.example.petstoremobile.fragments.ListFragment; -import com.example.petstoremobile.fragments.listfragments.detailfragments.RefundDetailFragment; import com.example.petstoremobile.models.Sale; import java.util.ArrayList; import java.util.List; @@ -53,9 +53,12 @@ public class SaleFragment extends Fragment implements SaleAdapter.OnSaleClickLis // Make the hamburger button open the drawer from listFragment if (btnHamburger != null) { btnHamburger.setOnClickListener(v -> { - ListFragment listFragment = (ListFragment) getParentFragment(); - if (listFragment != null) { - listFragment.openDrawer(); + Fragment parent = getParentFragment(); + if (parent != null) { + Fragment grandParent = parent.getParentFragment(); + if (grandParent instanceof ListFragment) { + ((ListFragment) grandParent).openDrawer(); + } } }); } @@ -111,19 +114,14 @@ public class SaleFragment extends Fragment implements SaleAdapter.OnSaleClickLis @Override public void onSaleClick(int position) { Sale sale = filteredList.get(position); - RefundDetailFragment refundFragment = new RefundDetailFragment(); Bundle args = new Bundle(); args.putInt("saleId", sale.getSaleId()); args.putString("saleDate", sale.getSaleDate()); args.putString("employeeName", sale.getEmployeeName()); args.putDouble("total", sale.getTotal()); args.putString("paymentMethod", sale.getPaymentMethod()); - refundFragment.setArguments(args); - refundFragment.setSaleFragment(this); - - ListFragment listFragment = (ListFragment) getParentFragment(); - if (listFragment != null) - listFragment.loadFragment(refundFragment); + + NavHostFragment.findNavController(this).navigate(R.id.nav_refund_detail, args); } public void reloadSales() { @@ -149,4 +147,4 @@ public class SaleFragment extends Fragment implements SaleAdapter.OnSaleClickLis recyclerView.setLayoutManager(new LinearLayoutManager(getContext())); recyclerView.setAdapter(adapter); } -} \ No newline at end of file +} 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 afa793de..dc9ef0fe 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 @@ -2,7 +2,10 @@ package com.example.petstoremobile.fragments.listfragments; import android.os.Bundle; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; +import androidx.navigation.fragment.NavHostFragment; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; @@ -23,7 +26,6 @@ import com.example.petstoremobile.api.ServiceApi; import com.example.petstoremobile.dtos.PageResponse; import com.example.petstoremobile.dtos.ServiceDTO; import com.example.petstoremobile.fragments.ListFragment; -import com.example.petstoremobile.fragments.listfragments.detailfragments.ServiceDetailFragment; import com.google.android.material.floatingactionbutton.FloatingActionButton; import java.util.ArrayList; @@ -66,10 +68,12 @@ public class ServiceFragment extends Fragment implements ServiceAdapter.OnServic //Make the hamburger button open the drawer from listFragment hamburger.setOnClickListener(v -> { - ListFragment listFragment = (ListFragment) getParentFragment(); - //if list fragment is found then use its helper function to open the drawer - if (listFragment != null) { - listFragment.openDrawer(); + Fragment parent = getParentFragment(); + if (parent != null) { + Fragment grandParent = parent.getParentFragment(); + if (grandParent instanceof ListFragment) { + ((ListFragment) grandParent).openDrawer(); + } } }); @@ -112,8 +116,6 @@ public class ServiceFragment extends Fragment implements ServiceAdapter.OnServic //Open the service detail view depending on the mode private void openServiceDetails(int position) { - ServiceDetailFragment detailFragment = new ServiceDetailFragment(); - //Make a bundle to pass data to the detail fragment Bundle args = new Bundle(); args.putInt("position", position); @@ -128,16 +130,7 @@ public class ServiceFragment extends Fragment implements ServiceAdapter.OnServic args.putDouble("servicePrice", service.getServicePrice()); } - //send the bundle to the detail fragment to display - detailFragment.setArguments(args); - //set the service fragment to the parent so we refer back to service view when save or delete is done - detailFragment.setServiceFragment(this); - - //get ListFragment to load the the detail view - ListFragment listFragment = (ListFragment) getParentFragment(); - if (listFragment != null) { - listFragment.loadFragment(detailFragment); - } + NavHostFragment.findNavController(this).navigate(R.id.nav_service_detail, args); } // Called by ServiceAdapter when a row is clicked to open the details view @@ -188,4 +181,4 @@ public class ServiceFragment extends Fragment implements ServiceAdapter.OnServic recyclerView.setLayoutManager(new LinearLayoutManager(getContext())); recyclerView.setAdapter(adapter); } -} \ No newline at end of file +} 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 66b72b8b..f9de9227 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 @@ -2,7 +2,10 @@ package com.example.petstoremobile.fragments.listfragments; import android.os.Bundle; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; +import androidx.navigation.fragment.NavHostFragment; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; @@ -23,7 +26,6 @@ import com.example.petstoremobile.api.SupplierApi; import com.example.petstoremobile.dtos.PageResponse; import com.example.petstoremobile.dtos.SupplierDTO; import com.example.petstoremobile.fragments.ListFragment; -import com.example.petstoremobile.fragments.listfragments.detailfragments.SupplierDetailFragment; import com.google.android.material.floatingactionbutton.FloatingActionButton; import java.util.ArrayList; @@ -66,10 +68,12 @@ public class SupplierFragment extends Fragment implements SupplierAdapter.OnSupp //Make the hamburger button open the drawer from listFragment hamburger.setOnClickListener(v -> { - ListFragment listFragment = (ListFragment) getParentFragment(); - //if list fragment is found then use its helper function to open the drawer - if (listFragment != null) { - listFragment.openDrawer(); + Fragment parent = getParentFragment(); + if (parent != null) { + Fragment grandParent = parent.getParentFragment(); + if (grandParent instanceof ListFragment) { + ((ListFragment) grandParent).openDrawer(); + } } }); @@ -113,8 +117,6 @@ public class SupplierFragment extends Fragment implements SupplierAdapter.OnSupp //Open the supplier detail view depending on the mode private void openSupplierDetails(int position) { - SupplierDetailFragment detailFragment = new SupplierDetailFragment(); - //Make a bundle to pass data to the detail fragment Bundle args = new Bundle(); args.putInt("position", position); @@ -130,16 +132,7 @@ public class SupplierFragment extends Fragment implements SupplierAdapter.OnSupp args.putString("supPhone", supplier.getSupPhone()); } - //send the bundle to the detail fragment to display - detailFragment.setArguments(args); - //set the supplier fragment to the parent so we refer back to supplier view when save or delete is done - detailFragment.setSupplierFragment(this); - - //get ListFragment to load the the detail view - ListFragment listFragment = (ListFragment) getParentFragment(); - if (listFragment != null) { - listFragment.loadFragment(detailFragment); - } + NavHostFragment.findNavController(this).navigate(R.id.nav_supplier_detail, args); } 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 512427d5..a9167678 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 @@ -8,6 +8,8 @@ import android.widget.*; import androidx.annotation.NonNull; import androidx.appcompat.app.AlertDialog; import androidx.fragment.app.Fragment; +import androidx.navigation.fragment.NavHostFragment; + import com.example.petstoremobile.R; import com.example.petstoremobile.adapters.BlackTextArrayAdapter; import com.example.petstoremobile.api.*; @@ -259,7 +261,6 @@ public class AdoptionDetailFragment extends Fragment { } private void navigateBack() { - ListFragment lf = (ListFragment) getParentFragment(); - if (lf != null) lf.getChildFragmentManager().popBackStack(); + NavHostFragment.findNavController(this).popBackStack(); } -} \ No newline at end of file +} 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 51e37666..45ffe85a 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 @@ -8,6 +8,8 @@ import android.widget.*; import androidx.annotation.NonNull; import androidx.appcompat.app.AlertDialog; import androidx.fragment.app.Fragment; +import androidx.navigation.fragment.NavHostFragment; + import com.example.petstoremobile.R; import com.example.petstoremobile.adapters.BlackTextArrayAdapter; import com.example.petstoremobile.api.*; @@ -447,7 +449,6 @@ public class AppointmentDetailFragment extends Fragment { } private void navigateBack() { - ListFragment lf = (ListFragment) getParentFragment(); - if (lf != null) lf.getChildFragmentManager().popBackStack(); + NavHostFragment.findNavController(this).popBackStack(); } -} \ No newline at end of file +} 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 c1bb052d..92fecd47 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 @@ -16,6 +16,7 @@ import android.widget.Toast; import androidx.appcompat.app.AlertDialog; import androidx.fragment.app.Fragment; +import androidx.navigation.fragment.NavHostFragment; import com.example.petstoremobile.R; import com.example.petstoremobile.adapters.BlackTextArrayAdapter; @@ -327,9 +328,7 @@ public class InventoryDetailFragment extends Fragment { } private void navigateBack() { - ListFragment lf = (ListFragment) getParentFragment(); - if (lf != null) - lf.getChildFragmentManager().popBackStack(); + NavHostFragment.findNavController(this).popBackStack(); } private void setButtonsEnabled(boolean enabled) { @@ -337,4 +336,4 @@ public class InventoryDetailFragment extends Fragment { btnDelete.setEnabled(enabled); btnBack.setEnabled(enabled); } -} \ No newline at end of file +} diff --git a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/PetDetailFragment.java b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/PetDetailFragment.java index 7f9a44f1..8aa3b319 100644 --- a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/PetDetailFragment.java +++ b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/PetDetailFragment.java @@ -7,6 +7,7 @@ import androidx.annotation.Nullable; import androidx.appcompat.app.AlertDialog; import androidx.core.content.ContextCompat; import androidx.fragment.app.Fragment; +import androidx.navigation.fragment.NavHostFragment; import android.util.Log; import android.view.LayoutInflater; @@ -44,15 +45,9 @@ public class PetDetailFragment extends Fragment { private Button btnSavePet, btnDeletePet, btnBack; private int petId; private boolean isEditing = false; - private PetFragment petFragment; @Inject PetApi petApi; - //set the pet fragment to the parent so we refer back to pet view when save or delete is done - public void setPetFragment(PetFragment fragment) { - this.petFragment = fragment; - } - @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -178,14 +173,7 @@ public class PetDetailFragment extends Fragment { //Helper method to navigate back to the list private void navigateBack() { - ListFragment listFragment = (ListFragment) getParentFragment(); - if (listFragment != null) { - // If editing pop back twice to get back to PetDetail Fragment instead of PetProfileFragment - if (isEditing) { - listFragment.getChildFragmentManager().popBackStack(); - } - listFragment.getChildFragmentManager().popBackStack(); - } + NavHostFragment.findNavController(this).popBackStack(); } //helper function to check if pet is being edited or added and show the view accordingly @@ -244,4 +232,4 @@ public class PetDetailFragment extends Fragment { spinnerPetStatus.setAdapter(adapter); } -} \ No newline at end of file +} 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 228f2c01..bf13d685 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 @@ -17,13 +17,17 @@ import androidx.appcompat.app.AlertDialog; import androidx.core.content.ContextCompat; import androidx.core.content.FileProvider; import androidx.fragment.app.Fragment; +import androidx.navigation.fragment.NavHostFragment; + import com.bumptech.glide.Glide; import com.bumptech.glide.load.engine.DiskCacheStrategy; +import com.bumptech.glide.load.model.GlideUrl; +import com.bumptech.glide.load.model.LazyHeaders; import com.example.petstoremobile.R; import com.example.petstoremobile.adapters.BlackTextArrayAdapter; import com.example.petstoremobile.api.*; +import com.example.petstoremobile.api.auth.TokenManager; import com.example.petstoremobile.dtos.*; -import com.example.petstoremobile.fragments.ListFragment; import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; @@ -59,6 +63,7 @@ public class ProductDetailFragment extends Fragment { @Inject ProductApi productApi; @Inject CategoryApi categoryApi; @Inject @Named("baseUrl") String baseUrl; + @Inject TokenManager tokenManager; private ActivityResultLauncher galleryLauncher; private ActivityResultLauncher cameraLauncher; @@ -254,10 +259,18 @@ public class ProductDetailFragment extends Fragment { //load the product image from the backend private void loadProductImage() { String imageUrl = baseUrl + String.format(Locale.US, ProductApi.PRODUCT_IMAGE_PATH, prodId); + String token = tokenManager.getToken(); + + Object loadTarget = imageUrl; + if (token != null) { + loadTarget = new GlideUrl(imageUrl, new LazyHeaders.Builder() + .addHeader("Authorization", "Bearer " + token) + .build()); + } + Glide.with(this) - .load(imageUrl) - .diskCacheStrategy(DiskCacheStrategy.NONE) - .skipMemoryCache(true) + .load(loadTarget) + .diskCacheStrategy(DiskCacheStrategy.ALL) .placeholder(R.drawable.placeholder2) .error(R.drawable.placeholder2) .into(ivProductImage); @@ -398,7 +411,6 @@ public class ProductDetailFragment extends Fragment { } private void navigateBack() { - ListFragment lf = (ListFragment) getParentFragment(); - if (lf != null) lf.getChildFragmentManager().popBackStack(); + NavHostFragment.findNavController(this).popBackStack(); } } \ No newline at end of file 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 909df42c..d934f64f 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 @@ -7,6 +7,8 @@ import android.widget.*; import androidx.annotation.NonNull; import androidx.appcompat.app.AlertDialog; import androidx.fragment.app.Fragment; +import androidx.navigation.fragment.NavHostFragment; + import com.example.petstoremobile.R; import com.example.petstoremobile.adapters.BlackTextArrayAdapter; import com.example.petstoremobile.api.*; @@ -222,7 +224,6 @@ public class ProductSupplierDetailFragment extends Fragment { } private void navigateBack() { - ListFragment lf = (ListFragment) getParentFragment(); - if (lf != null) lf.getChildFragmentManager().popBackStack(); + NavHostFragment.findNavController(this).popBackStack(); } -} \ No newline at end of file +} 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 eec648e2..38da2aa4 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 @@ -6,6 +6,8 @@ import android.view.*; import android.widget.*; import androidx.annotation.NonNull; import androidx.fragment.app.Fragment; +import androidx.navigation.fragment.NavHostFragment; + import com.example.petstoremobile.R; import com.example.petstoremobile.fragments.ListFragment; @@ -49,8 +51,7 @@ public class PurchaseOrderDetailFragment extends Fragment { } btnBack.setOnClickListener(v -> { - ListFragment lf = (ListFragment) getParentFragment(); - if (lf != null) lf.getChildFragmentManager().popBackStack(); + NavHostFragment.findNavController(this).popBackStack(); }); return view; diff --git a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/RefundDetailFragment.java b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/RefundDetailFragment.java index 190c89c5..ce782a04 100644 --- a/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/RefundDetailFragment.java +++ b/android/app/src/main/java/com/example/petstoremobile/fragments/listfragments/detailfragments/RefundDetailFragment.java @@ -2,6 +2,8 @@ package com.example.petstoremobile.fragments.listfragments.detailfragments; import android.os.Bundle; import androidx.fragment.app.Fragment; +import androidx.navigation.fragment.NavHostFragment; + import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -14,7 +16,6 @@ import android.widget.Toast; import com.example.petstoremobile.R; import com.example.petstoremobile.adapters.BlackTextArrayAdapter; import com.example.petstoremobile.api.SaleApi; -import com.example.petstoremobile.fragments.ListFragment; import com.example.petstoremobile.fragments.listfragments.SaleFragment; import com.example.petstoremobile.utils.ActivityLogger; import com.example.petstoremobile.utils.InputValidator; @@ -119,9 +120,7 @@ public class RefundDetailFragment extends Fragment { } private void goBack() { - ListFragment listFragment = (ListFragment) getParentFragment(); - if (listFragment != null) - listFragment.getChildFragmentManager().popBackStack(); + NavHostFragment.findNavController(this).popBackStack(); } private void initViews(View view) { @@ -141,4 +140,4 @@ public class RefundDetailFragment extends Fragment { adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); spinnerRefundPayment.setAdapter(adapter); } -} \ No newline at end of file +} 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 4176fa38..fc65a1e1 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 @@ -4,6 +4,7 @@ import android.os.Bundle; import androidx.appcompat.app.AlertDialog; import androidx.fragment.app.Fragment; +import androidx.navigation.fragment.NavHostFragment; import android.util.Log; import android.view.LayoutInflater; @@ -17,7 +18,6 @@ import android.widget.Toast; import com.example.petstoremobile.R; import com.example.petstoremobile.api.ServiceApi; import com.example.petstoremobile.dtos.ServiceDTO; -import com.example.petstoremobile.fragments.ListFragment; import com.example.petstoremobile.fragments.listfragments.ServiceFragment; import com.example.petstoremobile.utils.ActivityLogger; import com.example.petstoremobile.utils.InputValidator; @@ -164,10 +164,7 @@ public class ServiceDetailFragment extends Fragment { //Helper method to navigate back to the list private void navigateBack() { - ListFragment listFragment = (ListFragment) getParentFragment(); - if (listFragment != null) { - listFragment.getChildFragmentManager().popBackStack(); - } + NavHostFragment.findNavController(this).popBackStack(); } //helper function to check if service is being edited or added and show the view accordingly 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 6125ddc5..e1651c1a 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 @@ -4,6 +4,7 @@ import android.os.Bundle; import androidx.appcompat.app.AlertDialog; import androidx.fragment.app.Fragment; +import androidx.navigation.fragment.NavHostFragment; import android.util.Log; import android.view.LayoutInflater; @@ -17,8 +18,6 @@ import android.widget.Toast; import com.example.petstoremobile.R; import com.example.petstoremobile.api.SupplierApi; import com.example.petstoremobile.dtos.SupplierDTO; -import com.example.petstoremobile.fragments.ListFragment; -import com.example.petstoremobile.fragments.listfragments.SupplierFragment; import com.example.petstoremobile.utils.ActivityLogger; import com.example.petstoremobile.utils.InputValidator; @@ -37,15 +36,9 @@ public class SupplierDetailFragment extends Fragment { private Button btnSaveSupplier, btnDeleteSupplier, btnBack; private int supId; private boolean isEditing = false; - private SupplierFragment supplierFragment; @Inject SupplierApi supplierApi; - //set the supplier fragment to the parent so we refer back to supplier view when save or delete is done - public void setSupplierFragment(SupplierFragment fragment) { - this.supplierFragment = fragment; - } - @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -167,10 +160,7 @@ public class SupplierDetailFragment extends Fragment { //Helper method to navigate back to the list private void navigateBack() { - ListFragment listFragment = (ListFragment) getParentFragment(); - if (listFragment != null) { - listFragment.getChildFragmentManager().popBackStack(); - } + NavHostFragment.findNavController(this).popBackStack(); } //helper function to check if supplier is being edited or added and show the view accordingly @@ -217,4 +207,4 @@ public class SupplierDetailFragment extends Fragment { btnDeleteSupplier = view.findViewById(R.id.btnDeleteSupplier); btnBack = view.findViewById(R.id.btnBack); } -} \ No newline at end of file +} 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 bf51556a..e8accaaf 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 @@ -14,6 +14,7 @@ import androidx.appcompat.app.AlertDialog; import androidx.core.content.ContextCompat; import androidx.core.content.FileProvider; import androidx.fragment.app.Fragment; +import androidx.navigation.fragment.NavHostFragment; import android.provider.MediaStore; import android.util.Log; @@ -27,8 +28,11 @@ import android.widget.Toast; import com.bumptech.glide.Glide; import com.bumptech.glide.load.engine.DiskCacheStrategy; +import com.bumptech.glide.load.model.GlideUrl; +import com.bumptech.glide.load.model.LazyHeaders; import com.example.petstoremobile.R; import com.example.petstoremobile.api.PetApi; +import com.example.petstoremobile.api.auth.TokenManager; import com.example.petstoremobile.fragments.ListFragment; import com.example.petstoremobile.fragments.listfragments.detailfragments.PetDetailFragment; @@ -62,6 +66,7 @@ public class PetProfileFragment extends Fragment { @Inject PetApi petApi; @Inject @Named("baseUrl") String baseUrl; + @Inject TokenManager tokenManager; // launchers for camera and gallery private ActivityResultLauncher galleryLauncher; @@ -148,26 +153,13 @@ public class PetProfileFragment extends Fragment { //set button click listeners btnBack.setOnClickListener(v -> { - //get the list fragment and pop the back stack to return to the previous view (PetFragment) - ListFragment listFragment = (ListFragment) getParentFragment(); - if (listFragment != null) { - listFragment.getChildFragmentManager().popBackStack(); - } + NavHostFragment.findNavController(this).popBackStack(); }); //Make the edit button go to the pet detail view btnEditPet.setOnClickListener(v -> { if (getArguments() == null) return; - - PetDetailFragment detailFragment = new PetDetailFragment(); - //send the bundle to the pet detail fragment - detailFragment.setArguments(getArguments()); - - //get ListFragment to load the the detail view - ListFragment listFragment = (ListFragment) getParentFragment(); - if (listFragment != null) { - listFragment.loadFragment(detailFragment); - } + NavHostFragment.findNavController(this).navigate(R.id.nav_pet_detail, getArguments()); }); //Make change photo button ask user to select a new photo @@ -209,11 +201,18 @@ public class PetProfileFragment extends Fragment { // Helper function to load pet image from backend private void loadPetImage(int petId) { String imageUrl = baseUrl + String.format(Locale.US, PetApi.PET_IMAGE_PATH, petId); + String token = tokenManager.getToken(); + + Object loadTarget = imageUrl; + if (token != null) { + loadTarget = new GlideUrl(imageUrl, new LazyHeaders.Builder() + .addHeader("Authorization", "Bearer " + token) + .build()); + } Glide.with(this) - .load(imageUrl) - .diskCacheStrategy(DiskCacheStrategy.NONE) - .skipMemoryCache(true) + .load(loadTarget) + .diskCacheStrategy(DiskCacheStrategy.ALL) .placeholder(R.drawable.placeholder) .error(R.drawable.placeholder) .listener(new com.bumptech.glide.request.RequestListener() { diff --git a/android/app/src/main/res/layout/activity_home.xml b/android/app/src/main/res/layout/activity_home.xml index 9c61c329..f5e822e2 100644 --- a/android/app/src/main/res/layout/activity_home.xml +++ b/android/app/src/main/res/layout/activity_home.xml @@ -7,12 +7,14 @@ android:orientation="vertical" android:background="@color/primary_dark"> - + app:defaultNavHost="true" + app:navGraph="@navigation/nav_graph" /> @@ -10,10 +11,13 @@ android:layout_height="match_parent" android:background="@color/background_grey"> - + android:layout_height="match_parent" + app:defaultNavHost="false" + app:navGraph="@navigation/list_nav_graph" /> - - - - - - - - - - - - - - - - - - + android:layout_height="48dp" + android:orientation="horizontal" + android:gravity="center_vertical" + android:paddingStart="16dp" + android:paddingEnd="16dp" + android:background="?attr/selectableItemBackground"> + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - + android:layout_height="wrap_content" + android:text="Sale" + android:textColor="@color/white" + android:textSize="15sp"/> + + + + + + - - - - + \ No newline at end of file diff --git a/android/app/src/main/res/navigation/list_nav_graph.xml b/android/app/src/main/res/navigation/list_nav_graph.xml new file mode 100644 index 00000000..7273dd5f --- /dev/null +++ b/android/app/src/main/res/navigation/list_nav_graph.xml @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/res/navigation/nav_graph.xml b/android/app/src/main/res/navigation/nav_graph.xml new file mode 100644 index 00000000..d104e4d5 --- /dev/null +++ b/android/app/src/main/res/navigation/nav_graph.xml @@ -0,0 +1,26 @@ + + + + + + + + + + \ No newline at end of file diff --git a/android/build.gradle.kts b/android/build.gradle.kts index 91c68295..3898c951 100644 --- a/android/build.gradle.kts +++ b/android/build.gradle.kts @@ -2,4 +2,5 @@ plugins { alias(libs.plugins.android.application) apply false alias(libs.plugins.hilt) apply false + alias(libs.plugins.navigation.safeargs) apply false } \ No newline at end of file diff --git a/android/gradle/libs.versions.toml b/android/gradle/libs.versions.toml index 8e1b4f14..c7a01abf 100644 --- a/android/gradle/libs.versions.toml +++ b/android/gradle/libs.versions.toml @@ -9,6 +9,7 @@ activity = "1.12.4" constraintlayout = "2.2.1" swiperefreshlayout = "1.2.0" hilt = "2.51.1" +navigation = "2.8.8" [libraries] junit = { group = "junit", name = "junit", version.ref = "junit" } @@ -21,7 +22,10 @@ constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayo swiperefreshlayout = { group = "androidx.swiperefreshlayout", name = "swiperefreshlayout", version.ref = "swiperefreshlayout" } hilt-android = { group = "com.google.dagger", name = "hilt-android", version.ref = "hilt" } hilt-compiler = { group = "com.google.dagger", name = "hilt-compiler", version.ref = "hilt" } +navigation-fragment = { group = "androidx.navigation", name = "navigation-fragment", version.ref = "navigation" } +navigation-ui = { group = "androidx.navigation", name = "navigation-ui", version.ref = "navigation" } [plugins] android-application = { id = "com.android.application", version.ref = "agp" } hilt = { id = "com.google.dagger.hilt.android", version.ref = "hilt" } +navigation-safeargs = { id = "androidx.navigation.safeargs", version.ref = "navigation" }