From 03ce5ca0909d492dde5e772cb2c4adc2873d78c0 Mon Sep 17 00:00:00 2001 From: Alex <78383757+Lextical@users.noreply.github.com> Date: Mon, 9 Mar 2026 22:38:56 -0600 Subject: [PATCH 1/2] add pet profile to pet list --- app/src/main/AndroidManifest.xml | 2 +- .../activities/HomeActivity.java | 4 +- .../activities/MainActivity.java | 1 - .../fragments/listfragments/PetFragment.java | 80 +++--- .../PetProfileFragment.java | 177 +++++++++++++ .../main/res/layout/fragment_pet_profile.xml | 244 ++++++++++++++++++ 6 files changed, 468 insertions(+), 40 deletions(-) create mode 100644 app/src/main/java/com/example/petstoremobile/fragments/listfragments/listprofilefragments/PetProfileFragment.java create mode 100644 app/src/main/res/layout/fragment_pet_profile.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 1e0ba27f..016d3601 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -23,7 +23,7 @@ android:theme="@style/Theme.PetStoreMobile"> { if (item.getItemId() == R.id.nav_list) { diff --git a/app/src/main/java/com/example/petstoremobile/activities/MainActivity.java b/app/src/main/java/com/example/petstoremobile/activities/MainActivity.java index c57caec1..974983da 100644 --- a/app/src/main/java/com/example/petstoremobile/activities/MainActivity.java +++ b/app/src/main/java/com/example/petstoremobile/activities/MainActivity.java @@ -9,7 +9,6 @@ import android.widget.Toast; import androidx.activity.EdgeToEdge; import androidx.appcompat.app.AppCompatActivity; -import androidx.core.content.ContextCompat; import androidx.core.graphics.Insets; import androidx.core.view.ViewCompat; import androidx.core.view.WindowInsetsCompat; diff --git a/app/src/main/java/com/example/petstoremobile/fragments/listfragments/PetFragment.java b/app/src/main/java/com/example/petstoremobile/fragments/listfragments/PetFragment.java index d436538e..6fc7f472 100644 --- a/app/src/main/java/com/example/petstoremobile/fragments/listfragments/PetFragment.java +++ b/app/src/main/java/com/example/petstoremobile/fragments/listfragments/PetFragment.java @@ -15,6 +15,7 @@ import com.example.petstoremobile.R; import com.example.petstoremobile.adapters.PetAdapter; import com.example.petstoremobile.fragments.ListFragment; import com.example.petstoremobile.fragments.listfragments.detailfragments.PetDetailFragment; +import com.example.petstoremobile.fragments.listfragments.listprofilefragments.PetProfileFragment; import com.example.petstoremobile.models.Pet; import com.google.android.material.floatingactionbutton.FloatingActionButton; @@ -54,31 +55,35 @@ public class PetFragment extends Fragment implements PetAdapter.OnPetClickListen return view; } - //Open the pet detail view depending on the mode + //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(); + Pet pet = petList.get(position); + args.putInt("petId", pet.getPetId()); + args.putString("petName", pet.getPetName()); + args.putString("petSpecies", pet.getPetSpecies()); + args.putString("petBreed", pet.getPetBreed()); + args.putInt("petAge", pet.getPetAge()); + args.putString("petStatus", pet.getPetStatus()); + args.putDouble("petPrice", pet.getPetPrice()); + + //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 (profileFragment != null) { + listFragment.loadFragment(profileFragment); + } + } + + //Open the pet detail view for adding private void openPetDetails(int position) { PetDetailFragment detailFragment = new PetDetailFragment(); - //Make a bundle to pass data to the detail fragment - Bundle args = new Bundle(); - args.putInt("position", position); - - //if editing a pet, add the pet data to the bundle - if (position != -1) { - Pet pet = petList.get(position); - args.putInt("petId", pet.getPetId()); - args.putString("petName", pet.getPetName()); - args.putString("petSpecies", pet.getPetSpecies()); - args.putString("petBreed", pet.getPetBreed()); - args.putInt("petAge", pet.getPetAge()); - args.putString("petStatus", pet.getPetStatus()); - args.putDouble("petPrice", pet.getPetPrice()); - } - - //send the bundle to the detail fragment to display - detailFragment.setArguments(args); - //set the pet fragment to the parent so we refer back to pet view when save or delete is done - detailFragment.setPetFragment(this); - //get ListFragment to load the the detail view ListFragment listFragment = (ListFragment) getParentFragment(); if (listFragment != null) { @@ -87,25 +92,26 @@ public class PetFragment extends Fragment implements PetAdapter.OnPetClickListen } // Called by PetDetailFragment when save or delete is done - public void onPetSaved(int position, Pet pet) { - if (position == -1) { - petList.add(pet); - adapter.notifyItemInserted(petList.size() - 1); - } else { - petList.set(position, pet); - adapter.notifyItemChanged(position); - } - } - - public void onPetDeleted(int position) { - petList.remove(position); - adapter.notifyItemRemoved(position); - } + //TODO: REPLACE THIS WITH JUST RELOADING THE LIST BY FETCHING FROM THE BACKEND +// public void onPetSaved(int position, Pet pet) { +// if (position == -1) { +// petList.add(pet); +// adapter.notifyItemInserted(petList.size() - 1); +// } else { +// petList.set(position, pet); +// adapter.notifyItemChanged(position); +// } +// } +// +// public void onPetDeleted(int position) { +// petList.remove(position); +// adapter.notifyItemRemoved(position); +// } // Called by PetAdapter when a row is clicked to open the details view @Override public void onPetClick(int position) { - openPetDetails(position); + openPetProfile(position); } // Helper function to get a list of all pets (Loads hardcoded sample data for now) TODO: REPLACE THIS WITH A METHOD THAT GETS DATA FROM THE DATABASE diff --git a/app/src/main/java/com/example/petstoremobile/fragments/listfragments/listprofilefragments/PetProfileFragment.java b/app/src/main/java/com/example/petstoremobile/fragments/listfragments/listprofilefragments/PetProfileFragment.java new file mode 100644 index 00000000..280789e8 --- /dev/null +++ b/app/src/main/java/com/example/petstoremobile/fragments/listfragments/listprofilefragments/PetProfileFragment.java @@ -0,0 +1,177 @@ +package com.example.petstoremobile.fragments.listfragments.listprofilefragments; + +import android.Manifest; +import android.app.Activity; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.graphics.Color; +import android.net.Uri; +import android.os.Bundle; + +import androidx.activity.result.ActivityResultLauncher; +import androidx.activity.result.contract.ActivityResultContracts; +import androidx.appcompat.app.AlertDialog; +import androidx.core.content.ContextCompat; +import androidx.core.content.FileProvider; +import androidx.fragment.app.Fragment; + +import android.provider.MediaStore; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.TextView; + +import com.example.petstoremobile.R; +import com.example.petstoremobile.fragments.ListFragment; +import com.example.petstoremobile.fragments.listfragments.detailfragments.PetDetailFragment; + +import java.io.File; +import java.util.Locale; + +public class PetProfileFragment extends Fragment { + + private TextView tvPetName, tvPetSpecies, tvPetBreed, tvPetAge, tvPetPrice; + private Button btnBack, btnEditPet, btnChangePhoto; + private ImageView imgPet; + private Uri photoUri; + + // launchers for camera and gallery + private ActivityResultLauncher galleryLauncher; + private ActivityResultLauncher cameraLauncher; + private ActivityResultLauncher permissionLauncher; + + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + // Launcher to open gallery to select image + galleryLauncher = registerForActivityResult( + new ActivityResultContracts.StartActivityForResult(), + result -> { + if (result.getResultCode() == Activity.RESULT_OK && result.getData() != null) { + Uri selectedImage = result.getData().getData(); + imgPet.setImageURI(selectedImage); + // TODO: SAVE CHANGED PHOTO TO DATABASE + } + } + ); + + // Launcher for camera to open and capture image + cameraLauncher = registerForActivityResult( + new ActivityResultContracts.TakePicture(), + success -> { + if (success) { + imgPet.setImageURI(null); + imgPet.setImageURI(photoUri); + // TODO: SAVE CHANGED PHOTO TO DATABASE + } + } + ); + + // Launcher to request camera permission + permissionLauncher = registerForActivityResult( + new ActivityResultContracts.RequestPermission(), + granted -> { + if (granted) { + launchCamera(); + } else { + new AlertDialog.Builder(requireContext()) + .setTitle("Permission Required") + .setMessage("Please grant camera permission to use this feature") + .setPositiveButton("Open Settings", (dialog, which) -> { + Intent intent = new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + intent.setData(Uri.fromParts("package", requireContext().getPackageName(), null)); + startActivity(intent); + }) + .setNegativeButton("Cancel", null) + .show(); + } + } + ); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.fragment_pet_profile, container, false); + + // Initialize views + tvPetName = view.findViewById(R.id.tvPetName); + tvPetSpecies = view.findViewById(R.id.tvPetSpecies); + tvPetBreed = view.findViewById(R.id.tvPetBreed); + tvPetAge = view.findViewById(R.id.tvPetAge); + tvPetPrice = view.findViewById(R.id.tvPetPrice); + btnBack = view.findViewById(R.id.btnBack); + btnEditPet = view.findViewById(R.id.btnEditPet); + btnChangePhoto = view.findViewById(R.id.btnChangePhoto); + imgPet = view.findViewById(R.id.imgPet); + + + // Set pet details to display + if (getArguments() != null) { + tvPetName.setText(getArguments().getString("petName")); + tvPetSpecies.setText(getArguments().getString("petSpecies")); + tvPetBreed.setText(getArguments().getString("petBreed")); + tvPetAge.setText(String.format(Locale.getDefault(), "%d yr(s)", getArguments().getInt("petAge"))); + tvPetPrice.setText(String.format(Locale.getDefault(), "$%.2f", getArguments().getDouble("petPrice"))); + } + + //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(); + } + }); + + //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); + } + }); + + //Make change photo button ask user to select a new photo + btnChangePhoto.setOnClickListener(v -> { + new AlertDialog.Builder(requireContext()) + .setTitle("Change Pet Photo") + .setItems(new String[]{"Take Photo", "Choose from Gallery"}, (dialog, which) -> { + if (which == 0) { + // Choose Camera + //Checks if the user has granted the camera permission already + if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) { + //if the permission is already granted then launch the camera + launchCamera(); + } else { + //otherwise request the permission + permissionLauncher.launch(Manifest.permission.CAMERA); + } + } else { + Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI); + galleryLauncher.launch(intent); + } + }) + .show(); + }); + + return view; + } + + private void launchCamera() { + File photoFile = new File(requireContext().getCacheDir(), "pet_photo.jpg"); + photoUri = FileProvider.getUriForFile(requireContext(), requireContext().getPackageName() + ".fileprovider", photoFile); + cameraLauncher.launch(photoUri); + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_pet_profile.xml b/app/src/main/res/layout/fragment_pet_profile.xml new file mode 100644 index 00000000..b750bd29 --- /dev/null +++ b/app/src/main/res/layout/fragment_pet_profile.xml @@ -0,0 +1,244 @@ + + + + + + + + + +